diff options
author | Thomas Haller <thaller@redhat.com> | 2017-02-10 14:43:34 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-02-10 14:43:35 +0100 |
commit | f549307ca5f7a6bf3e925497472616c87c8d4cbe (patch) | |
tree | 6c191b03e2a63f2c20ed076db79f022ac8f5dcd2 | |
parent | f3504c9bc214aa32f7a498a1adb48b840be8809a (diff) | |
parent | ef6c393889551cdcf46c7db3a7d881817d0866e6 (diff) | |
download | NetworkManager-f549307ca5f7a6bf3e925497472616c87c8d4cbe.tar.gz |
all: merge branch 'th/device-pending-action-bgo777831' (part 3, connection-list)
Refactor core to return list of connections as array instead of GSList.
Also unify and cleanup the sorting of connections.
https://bugzilla.gnome.org/show_bug.cgi?id=777831
-rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 43 | ||||
-rw-r--r-- | src/nm-checkpoint.c | 10 | ||||
-rw-r--r-- | src/nm-core-utils.c | 64 | ||||
-rw-r--r-- | src/nm-core-utils.h | 2 | ||||
-rw-r--r-- | src/nm-manager.c | 109 | ||||
-rw-r--r-- | src/nm-manager.h | 5 | ||||
-rw-r--r-- | src/nm-policy.c | 110 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.c | 90 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.h | 5 | ||||
-rw-r--r-- | src/settings/nm-settings.c | 212 | ||||
-rw-r--r-- | src/settings/nm-settings.h | 21 | ||||
-rw-r--r-- | src/tests/test-general.c | 10 |
12 files changed, 379 insertions, 302 deletions
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index ce0c690e36..e70432ff64 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -1338,12 +1338,14 @@ check_scanning_allowed (NMDeviceWifi *self) static gboolean hidden_filter_func (NMSettings *settings, - NMConnection *connection, + NMSettingsConnection *connection, gpointer user_data) { NMSettingWireless *s_wifi; - s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (connection); + if (!nm_connection_is_type (NM_CONNECTION (connection), NM_SETTING_WIRELESS_SETTING_NAME)) + return FALSE; + s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (NM_CONNECTION (connection)); return s_wifi ? nm_setting_wireless_get_hidden (s_wifi) : FALSE; } @@ -1352,7 +1354,8 @@ build_hidden_probe_list (NMDeviceWifi *self) { NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); guint max_scan_ssids = nm_supplicant_interface_get_max_scan_ssids (priv->sup_iface); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i, len; GPtrArray *ssids = NULL; static GByteArray *nullssid = NULL; @@ -1360,28 +1363,31 @@ build_hidden_probe_list (NMDeviceWifi *self) if (max_scan_ssids < 2) return NULL; - /* Static wildcard SSID used for every scan */ + connections = nm_settings_get_connections_clone (nm_device_get_settings ((NMDevice *) self), + &len, + hidden_filter_func, + NULL); + if (!connections[0]) + return NULL; + + g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_timestamp_p_with_data, NULL); + + ssids = g_ptr_array_new_full (max_scan_ssids, (GDestroyNotify) g_byte_array_unref); + + /* Add wildcard SSID using a static wildcard SSID used for every scan */ if (G_UNLIKELY (nullssid == NULL)) nullssid = g_byte_array_new (); + g_ptr_array_add (ssids, g_byte_array_ref (nullssid)); - connections = nm_settings_get_best_connections (nm_device_get_settings ((NMDevice *) self), - max_scan_ssids - 1, - NM_SETTING_WIRELESS_SETTING_NAME, - NULL, - hidden_filter_func, - NULL); - if (connections && connections->data) { - ssids = g_ptr_array_new_full (max_scan_ssids - 1, (GDestroyNotify) g_byte_array_unref); - g_ptr_array_add (ssids, g_byte_array_ref (nullssid)); /* Add wildcard SSID */ - } - - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *connection = iter->data; + for (i = 0; connections[i]; i++) { NMSettingWireless *s_wifi; GBytes *ssid; GByteArray *ssid_array; - s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (connection); + if (i >= max_scan_ssids - 1) + break; + + s_wifi = (NMSettingWireless *) nm_connection_get_setting_wireless (NM_CONNECTION (connections[i])); g_assert (s_wifi); ssid = nm_setting_wireless_get_ssid (s_wifi); g_assert (ssid); @@ -1391,7 +1397,6 @@ build_hidden_probe_list (NMDeviceWifi *self) g_bytes_get_size (ssid)); g_ptr_array_add (ssids, ssid_array); } - g_slist_free (connections); return ssids; } diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index 7d89e61ef8..08242ac60f 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -249,14 +249,14 @@ next_dev: if (NM_FLAGS_HAS (priv->flags, NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS)) { NMSettingsConnection *con; - gs_free_slist GSList *list = NULL; - GSList *item; + gs_free NMSettingsConnection **list = NULL; + guint i; g_return_val_if_fail (priv->connection_uuids, NULL); - list = nm_settings_get_connections_sorted (nm_settings_get ()); + list = nm_settings_get_connections_sorted (nm_settings_get (), NULL); - for (item = list; item; item = g_slist_next (item)) { - con = item->data; + for (i = 0; list[i]; i++) { + con = list[i]; if (!g_hash_table_contains (priv->connection_uuids, nm_settings_connection_get_uuid (con))) { _LOGD ("rollback: deleting new connection %s (%s)", diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 352bde8a54..75c44b7865 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -1975,27 +1975,57 @@ nm_utils_read_resolv_conf_dns_options (const char *rc_contents) return options; } +/*****************************************************************************/ + +/** + * nm_utils_cmp_connection_by_autoconnect_priority: + * @a: + * @b: + * + * compare connections @a and @b for their autoconnect property + * (with sorting the connection that has autoconnect enabled before + * the other) + * If they both have autoconnect enabled, sort them depending on their + * autoconnect-priority (with the higher priority first). + * + * If their autoconnect/autoconnect-priority is the same, 0 is returned. + * That is, they compare equal. + * + * Returns: -1, 0, or 1 + */ int -nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnection **b) +nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection *b) { - NMSettingConnection *a_s_con, *b_s_con; - gboolean a_ac, b_ac; - gint a_ap, b_ap; - - a_s_con = nm_connection_get_setting_connection (*a); - b_s_con = nm_connection_get_setting_connection (*b); - - a_ac = !!nm_setting_connection_get_autoconnect (a_s_con); - b_ac = !!nm_setting_connection_get_autoconnect (b_s_con); - if (a_ac != b_ac) - return ((int) b_ac) - ((int) a_ac); - if (!a_ac) + NMSettingConnection *a_s_con; + NMSettingConnection *b_s_con; + int a_ap, b_ap; + gboolean can_autoconnect; + + if (a == b) return 0; + if (!a) + return 1; + if (!b) + return -1; - a_ap = nm_setting_connection_get_autoconnect_priority (a_s_con); - b_ap = nm_setting_connection_get_autoconnect_priority (b_s_con); - if (a_ap != b_ap) - return (a_ap > b_ap) ? -1 : 1; + a_s_con = nm_connection_get_setting_connection (a); + b_s_con = nm_connection_get_setting_connection (b); + + if (!a_s_con) + return !b_s_con ? 0 : 1; + if (!b_s_con) + return -1; + + can_autoconnect = !!nm_setting_connection_get_autoconnect (a_s_con); + if (can_autoconnect != (!!nm_setting_connection_get_autoconnect (b_s_con))) + return can_autoconnect ? -1 : 1; + + if (can_autoconnect) { + a_ap = nm_setting_connection_get_autoconnect_priority (a_s_con); + b_ap = nm_setting_connection_get_autoconnect_priority (b_s_con); + if (a_ap != b_ap) + return (a_ap > b_ap) ? -1 : 1; + } return 0; } diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index e039760e09..a1d9c2d462 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -272,7 +272,7 @@ const char *nm_utils_new_infiniband_name (char *name, const char *parent_name, i GPtrArray *nm_utils_read_resolv_conf_nameservers (const char *rc_contents); GPtrArray *nm_utils_read_resolv_conf_dns_options (const char *rc_contents); -int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnection **b); +int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection *a, NMConnection *b); void nm_utils_log_connection_diff (NMConnection *connection, NMConnection *diff_base, guint32 level, guint64 domain, const char *name, const char *prefix); diff --git a/src/nm-manager.c b/src/nm-manager.c index 1bad6925b2..b80d2da4bd 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -423,29 +423,34 @@ find_ac_for_connection (NMManager *manager, NMConnection *connection) return NULL; } +static gboolean +_get_activatable_connections_filter (NMSettings *settings, + NMSettingsConnection *connection, + gpointer user_data) +{ + return !find_ac_for_connection (user_data, NM_CONNECTION (connection)); +} + /* Filter out connections that are already active. * nm_settings_get_connections_sorted() returns sorted list. We need to preserve the * order so that we didn't change auto-activation order (recent timestamps * are first). * Caller is responsible for freeing the returned list with g_slist_free(). */ -GSList * -nm_manager_get_activatable_connections (NMManager *manager) +NMSettingsConnection ** +nm_manager_get_activatable_connections (NMManager *manager, guint *out_len, gboolean sort) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *all_connections = nm_settings_get_connections_sorted (priv->settings); - GSList *connections = NULL, *iter; - NMSettingsConnection *connection; + NMSettingsConnection **connections; + guint len; - for (iter = all_connections; iter; iter = iter->next) { - connection = iter->data; - - if (!find_ac_for_connection (manager, NM_CONNECTION (connection))) - connections = g_slist_prepend (connections, connection); - } - - g_slist_free (all_connections); - return g_slist_reverse (connections); + connections = nm_settings_get_connections_clone (priv->settings, &len, + _get_activatable_connections_filter, + manager); + if (sort && len > 1) + g_qsort_with_data (connections, len, sizeof (connections[0]), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); + NM_SET_OUT (out_len, len); + return connections; } static NMActiveConnection * @@ -1205,7 +1210,8 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMDeviceFactory *factory; - gs_free_slist GSList *connections = NULL; + gs_free NMSettingsConnection **connections = NULL; + guint i; GSList *iter; gs_free char *iface = NULL; NMDevice *device = NULL, *parent = NULL; @@ -1276,9 +1282,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection) } /* Create backing resources if the device has any autoconnect connections */ - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *candidate = iter->data; + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMConnection *candidate = NM_CONNECTION (connections[i]); NMSettingConnection *s_con; if (!nm_device_check_connection_compatible (device, candidate)) @@ -1307,13 +1313,14 @@ static void retry_connections_for_parent_device (NMManager *self, NMDevice *device) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; g_return_if_fail (device); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *candidate = iter->data; + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMConnection *candidate = NM_CONNECTION (connections[i]); gs_free_error GError *error = NULL; gs_free char *ifname = NULL; NMDevice *parent; @@ -1328,8 +1335,6 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device) } } } - - g_slist_free (connections); } static void @@ -1688,7 +1693,7 @@ static NMSettingsConnection * get_existing_connection (NMManager *self, NMDevice *device, gboolean *out_generated) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - gs_free_slist GSList *connections = nm_manager_get_activatable_connections (self); + gs_free_slist GSList *connections = NULL; NMConnection *connection = NULL; NMSettingsConnection *matched; NMSettingsConnection *added = NULL; @@ -1738,7 +1743,17 @@ get_existing_connection (NMManager *self, NMDevice *device, gboolean *out_genera * When no configured connection matches the generated connection, we keep * the generated connection instead. */ - connections = g_slist_reverse (g_slist_sort (connections, nm_settings_sort_connections)); + { + gs_free NMSettingsConnection **cons = NULL; + guint i, len; + + /* XXX: this code will go away soon. Copy the array over to a GSList + * and don't bother for now. */ + cons = nm_manager_get_activatable_connections (self, &len, FALSE); + for (i = len; i > 0; ) + connections = g_slist_prepend (connections, cons[--i]); + connections = g_slist_sort (connections, (GCompareFunc) nm_settings_connection_cmp_timestamp); + } matched = NM_SETTINGS_CONNECTION (nm_utils_match_connection (connections, connection, nm_device_has_carrier (device), @@ -2675,14 +2690,15 @@ ensure_master_active_connection (NMManager *self, * activate it on the device. */ if (master_state == NM_DEVICE_STATE_DISCONNECTED || !nm_device_is_real (master_device)) { - GSList *connections; + gs_free NMSettingsConnection **connections = NULL; + guint i; g_assert (master_connection == NULL); /* Find a compatible connection and activate this device using it */ - connections = nm_manager_get_activatable_connections (self); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (iter->data); + connections = nm_manager_get_activatable_connections (self, NULL, TRUE); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *candidate = connections[i]; /* Ensure eg bond/team slave and the candidate master is a * bond/team master @@ -2698,11 +2714,9 @@ ensure_master_active_connection (NMManager *self, master_device, subject, error); - g_slist_free (connections); return master_ac; } } - g_slist_free (connections); g_set_error (error, NM_MANAGER_ERROR, @@ -2775,7 +2789,8 @@ find_slaves (NMManager *manager, NMDevice *device) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); - GSList *all_connections, *iter; + gs_free NMSettingsConnection **all_connections = NULL; + guint i; GSList *slaves = NULL; NMSettingConnection *s_con; @@ -2786,11 +2801,11 @@ find_slaves (NMManager *manager, * even if a slave was already active, it might be deactivated during * master reactivation. */ - all_connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = all_connections; iter; iter = iter->next) { + all_connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; all_connections[i]; i++) { NMSettingsConnection *master_connection = NULL; NMDevice *master_device = NULL; - NMConnection *candidate = iter->data; + NMConnection *candidate = NM_CONNECTION (all_connections[i]); find_master (manager, candidate, NULL, &master_connection, &master_device, NULL, NULL); if ( (master_connection && master_connection == connection) @@ -2798,7 +2813,6 @@ find_slaves (NMManager *manager, slaves = g_slist_prepend (slaves, candidate); } } - g_slist_free (all_connections); return g_slist_reverse (slaves); } @@ -3813,7 +3827,17 @@ impl_manager_add_and_activate_connection (NMManager *self, if (!subject) goto error; - all_connections = nm_settings_get_connections_sorted (priv->settings); + { + gs_free NMSettingsConnection **connections = NULL; + guint i, len; + + connections = nm_settings_get_connections_sorted (priv->settings, &len); + all_connections = NULL; + for (i = len; i > 0; ) { + i--; + all_connections = g_slist_prepend (all_connections, connections[i]); + } + } if (vpn) { /* Try to fill the VPN's connection setting and name at least */ if (!nm_connection_get_setting_vpn (connection)) { @@ -4770,7 +4794,7 @@ gboolean nm_manager_start (NMManager *self, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter, *connections; + gs_free NMSettingsConnection **connections = NULL; guint i; if (!nm_settings_start (priv->settings, error)) @@ -4822,10 +4846,9 @@ nm_manager_start (NMManager *self, GError **error) * connection-added signals thus devices have to be created manually. */ _LOGD (LOGD_CORE, "creating virtual devices..."); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = iter->next) - connection_changed (self, NM_CONNECTION (iter->data)); - g_slist_free (connections); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) + connection_changed (self, NM_CONNECTION (connections[i])); priv->devices_inited = TRUE; diff --git a/src/nm-manager.h b/src/nm-manager.h index c69fc9e192..a7baf30986 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -84,7 +84,10 @@ gboolean nm_manager_start (NMManager *manager, void nm_manager_stop (NMManager *manager); NMState nm_manager_get_state (NMManager *manager); const GSList *nm_manager_get_active_connections (NMManager *manager); -GSList * nm_manager_get_activatable_connections (NMManager *manager); + +NMSettingsConnection **nm_manager_get_activatable_connections (NMManager *manager, + guint *out_len, + gboolean sort); void nm_manager_write_device_state (NMManager *manager); diff --git a/src/nm-policy.c b/src/nm-policy.c index a2ff2945b2..7050f93281 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -960,9 +960,8 @@ auto_activate_device (NMPolicy *self, NMPolicyPrivate *priv; NMSettingsConnection *best_connection; gs_free char *specific_object = NULL; - GPtrArray *connections; - GSList *connection_list; - guint i; + gs_free NMSettingsConnection **connections = NULL; + guint i, len; nm_assert (NM_IS_POLICY (self)); nm_assert (NM_IS_DEVICE (device)); @@ -976,21 +975,14 @@ auto_activate_device (NMPolicy *self, if (nm_device_get_act_request (device)) return; - connection_list = nm_manager_get_activatable_connections (priv->manager); - if (!connection_list) + connections = nm_manager_get_activatable_connections (priv->manager, &len, TRUE); + if (!connections[0]) return; - connections = _nm_utils_copy_slist_to_array (connection_list, NULL, NULL); - g_slist_free (connection_list); - - /* sort is stable (which is important at this point) so that connections - * with same priority are still sorted by last-connected-timestamp. */ - g_ptr_array_sort (connections, (GCompareFunc) nm_utils_cmp_connection_by_autoconnect_priority); - /* Find the first connection that should be auto-activated */ best_connection = NULL; - for (i = 0; i < connections->len; i++) { - NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (connections->pdata[i]); + for (i = 0; i < len; i++) { + NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (connections[i]); if (!nm_settings_connection_can_autoconnect (candidate)) continue; @@ -999,7 +991,6 @@ auto_activate_device (NMPolicy *self, break; } } - g_ptr_array_free (connections, TRUE); if (best_connection) { GError *error = NULL; @@ -1149,7 +1140,8 @@ static void reset_autoconnect_all (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; if (device) { _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections on %s", @@ -1157,41 +1149,43 @@ reset_autoconnect_all (NMPolicy *self, NMDevice *device) } else _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections"); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - if (!device || nm_device_check_connection_compatible (device, iter->data)) { - nm_settings_connection_reset_autoconnect_retries (iter->data); - nm_settings_connection_set_autoconnect_blocked_reason (iter->data, NM_DEVICE_STATE_REASON_NONE); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *connection = connections[i]; + + if (!device || nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) { + nm_settings_connection_reset_autoconnect_retries (connection); + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NONE); } } - g_slist_free (connections); } static void reset_autoconnect_for_failed_secrets (NMPolicy *self) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; _LOGD (LOGD_DEVICE, "re-enabling autoconnect for all connections with failed secrets"); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (iter->data); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *connection = connections[i]; if (nm_settings_connection_get_autoconnect_blocked_reason (connection) == NM_DEVICE_STATE_REASON_NO_SECRETS) { nm_settings_connection_reset_autoconnect_retries (connection); nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_NONE); } } - g_slist_free (connections); } static void block_autoconnect_for_device (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; _LOGD (LOGD_DEVICE, "blocking autoconnect for all connections on %s", nm_device_get_iface (device)); @@ -1203,14 +1197,15 @@ block_autoconnect_for_device (NMPolicy *self, NMDevice *device) if (!nm_device_is_software (device)) return; - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - if (nm_device_check_connection_compatible (device, iter->data)) { - nm_settings_connection_set_autoconnect_blocked_reason (NM_SETTINGS_CONNECTION (iter->data), + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *connection = connections[i]; + + if (nm_device_check_connection_compatible (device, NM_CONNECTION (connection))) { + nm_settings_connection_set_autoconnect_blocked_reason (connection, NM_DEVICE_STATE_REASON_USER_REQUESTED); } } - g_slist_free (connections); } static void @@ -1278,7 +1273,8 @@ reset_connections_retries (gpointer user_data) { NMPolicy *self = (NMPolicy *) user_data; NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); - GSList *connections, *iter; + gs_free NMSettingsConnection **connections = NULL; + guint i; gint32 con_stamp, min_stamp, now; gboolean changed = FALSE; @@ -1286,9 +1282,9 @@ reset_connections_retries (gpointer user_data) min_stamp = 0; now = nm_utils_get_monotonic_timestamp_s (); - connections = nm_settings_get_connections_sorted (priv->settings); - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMSettingsConnection *connection = NM_SETTINGS_CONNECTION (iter->data); + connections = nm_settings_get_connections_sorted (priv->settings, NULL); + for (i = 0; connections[i]; i++) { + NMSettingsConnection *connection = connections[i]; con_stamp = nm_settings_connection_get_autoconnect_retry_time (connection); if (con_stamp == 0) @@ -1300,7 +1296,6 @@ reset_connections_retries (gpointer user_data) } else if (min_stamp == 0 || min_stamp > con_stamp) min_stamp = con_stamp; } - g_slist_free (connections); /* Schedule the handler again if there are some stamps left */ if (min_stamp != 0) @@ -1318,8 +1313,7 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) { NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self); const char *master_device, *master_uuid_settings = NULL, *master_uuid_applied = NULL; - gs_free_slist GSList *connections = NULL; - GSList *iter; + guint i; NMActRequest *req; gboolean internal_activation = FALSE; @@ -1345,27 +1339,29 @@ activate_slave_connections (NMPolicy *self, NMDevice *device) internal_activation = subject && nm_auth_subject_is_internal (subject); } - if (!internal_activation) - connections = nm_settings_get_connections_sorted (priv->settings); + if (!internal_activation) { + gs_free NMSettingsConnection **connections = NULL; - for (iter = connections; iter; iter = g_slist_next (iter)) { - NMConnection *slave; - NMSettingConnection *s_slave_con; - const char *slave_master; + connections = nm_settings_get_connections_sorted (priv->settings, NULL); - slave = NM_CONNECTION (iter->data); - g_assert (slave); + for (i = 0; connections[i]; i++) { + NMConnection *slave; + NMSettingConnection *s_slave_con; + const char *slave_master; - s_slave_con = nm_connection_get_setting_connection (slave); - g_assert (s_slave_con); - slave_master = nm_setting_connection_get_master (s_slave_con); - if (!slave_master) - continue; + slave = NM_CONNECTION (connections[i]); - if ( !g_strcmp0 (slave_master, master_device) - || !g_strcmp0 (slave_master, master_uuid_applied) - || !g_strcmp0 (slave_master, master_uuid_settings)) - nm_settings_connection_reset_autoconnect_retries (NM_SETTINGS_CONNECTION (slave)); + s_slave_con = nm_connection_get_setting_connection (slave); + g_assert (s_slave_con); + slave_master = nm_setting_connection_get_master (s_slave_con); + if (!slave_master) + continue; + + if ( !g_strcmp0 (slave_master, master_device) + || !g_strcmp0 (slave_master, master_uuid_applied) + || !g_strcmp0 (slave_master, master_uuid_settings)) + nm_settings_connection_reset_autoconnect_retries (NM_SETTINGS_CONNECTION (slave)); + } } schedule_activate_all (self); diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 81dcb69898..9f70aaba26 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -2162,6 +2162,96 @@ nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConn /*****************************************************************************/ +static int +_cmp_timestamp (NMSettingsConnection *a, NMSettingsConnection *b) +{ + gboolean a_has_ts, b_has_ts; + guint64 ats = 0, bts = 0; + + nm_assert (NM_IS_SETTINGS_CONNECTION (a)); + nm_assert (NM_IS_SETTINGS_CONNECTION (b)); + + a_has_ts = !!nm_settings_connection_get_timestamp (a, &ats); + b_has_ts = !!nm_settings_connection_get_timestamp (b, &bts); + if (a_has_ts != b_has_ts) + return a_has_ts ? -1 : 1; + if (a_has_ts && ats != bts) + return (ats > bts) ? -1 : 1; + return 0; +} + +static int +_cmp_last_resort (NMSettingsConnection *a, NMSettingsConnection *b) +{ + int c; + + nm_assert (NM_IS_SETTINGS_CONNECTION (a)); + nm_assert (NM_IS_SETTINGS_CONNECTION (b)); + + c = g_strcmp0 (nm_connection_get_uuid (NM_CONNECTION (a)), + nm_connection_get_uuid (NM_CONNECTION (b))); + if (c) + return c; + + /* hm, same UUID. Use their pointer value to give them a stable + * order. */ + return (a > b) ? -1 : 1; +} + +/* sorting for "best" connections. + * The function sorts connections in descending timestamp order. + * That means an older connection (lower timestamp) goes after + * a newer one. + */ +int +nm_settings_connection_cmp_timestamp (NMSettingsConnection *a, NMSettingsConnection *b) +{ + int c; + + if (a == b) + return 0; + if (!a) + return 1; + if (!b) + return -1; + + if ((c = _cmp_timestamp (a, b))) + return c; + if ((c = nm_utils_cmp_connection_by_autoconnect_priority (NM_CONNECTION (a), NM_CONNECTION (b)))) + return c; + return _cmp_last_resort (a, b); +} + +int +nm_settings_connection_cmp_timestamp_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data) +{ + return nm_settings_connection_cmp_timestamp (*((NMSettingsConnection **) pa), + *((NMSettingsConnection **) pb)); +} + +int +nm_settings_connection_cmp_autoconnect_priority (NMSettingsConnection *a, NMSettingsConnection *b) +{ + int c; + + if (a == b) + return 0; + if ((c = nm_utils_cmp_connection_by_autoconnect_priority (NM_CONNECTION (a), NM_CONNECTION (b)))) + return c; + if ((c = _cmp_timestamp (a, b))) + return c; + return _cmp_last_resort (a, b); +} + +int +nm_settings_connection_cmp_autoconnect_priority_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data) +{ + return nm_settings_connection_cmp_autoconnect_priority (*((NMSettingsConnection **) pa), + *((NMSettingsConnection **) pb)); +} + +/*****************************************************************************/ + /** * nm_settings_connection_get_timestamp: * @self: the #NMSettingsConnection diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index c5ddd8173e..a2d6125734 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -184,6 +184,11 @@ NMSettingsConnectionFlags nm_settings_connection_get_flags (NMSettingsConnection NMSettingsConnectionFlags nm_settings_connection_set_flags (NMSettingsConnection *self, NMSettingsConnectionFlags flags, gboolean set); NMSettingsConnectionFlags nm_settings_connection_set_flags_all (NMSettingsConnection *self, NMSettingsConnectionFlags flags); +int nm_settings_connection_cmp_timestamp (NMSettingsConnection *ac, NMSettingsConnection *ab); +int nm_settings_connection_cmp_timestamp_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data); +int nm_settings_connection_cmp_autoconnect_priority (NMSettingsConnection *a, NMSettingsConnection *b); +int nm_settings_connection_cmp_autoconnect_priority_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data); + gboolean nm_settings_connection_get_timestamp (NMSettingsConnection *self, guint64 *out_timestamp); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 50b3b77222..cc03a2c4d9 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -393,35 +393,6 @@ error: g_clear_object (&subject); } -static int -connection_sort (gconstpointer pa, gconstpointer pb) -{ - NMConnection *a = NM_CONNECTION (pa); - NMSettingConnection *con_a; - NMConnection *b = NM_CONNECTION (pb); - NMSettingConnection *con_b; - guint64 ts_a = 0, ts_b = 0; - gboolean can_ac_a, can_ac_b; - - con_a = nm_connection_get_setting_connection (a); - g_assert (con_a); - con_b = nm_connection_get_setting_connection (b); - g_assert (con_b); - - can_ac_a = !!nm_setting_connection_get_autoconnect (con_a); - can_ac_b = !!nm_setting_connection_get_autoconnect (con_b); - if (can_ac_a != can_ac_b) - return can_ac_a ? -1 : 1; - - nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pa), &ts_a); - nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pb), &ts_b); - if (ts_a > ts_b) - return -1; - else if (ts_a == ts_b) - return 0; - return 1; -} - /** * nm_settings_get_connections: * @self: the #NMSettings @@ -447,46 +418,98 @@ nm_settings_get_connections (NMSettings *self, guint *out_len) priv = NM_SETTINGS_GET_PRIVATE (self); - if (priv->connections_cached_list) { + if (G_LIKELY (priv->connections_cached_list)) { NM_SET_OUT (out_len, g_hash_table_size (priv->connections)); return priv->connections_cached_list; } l = g_hash_table_size (priv->connections); - v = g_new (NMSettingsConnection *, l + 1); + v = g_new (NMSettingsConnection *, (gsize) l + 1); i = 0; g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &con)) + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &con)) { + nm_assert (i < l); v[i++] = con; - v[i] = NULL; - + } nm_assert (i == l); + v[i] = NULL; NM_SET_OUT (out_len, l); priv->connections_cached_list = v; return v; } +/** + * nm_settings_get_connections_clone: + * @self: the #NMSetting + * @out_len: (allow-none): optional output argument + * @func: caller-supplied function for filtering connections + * @func_data: caller-supplied data passed to @func + * + * Returns: (transfer container) (element-type NMSettingsConnection): + * an NULL terminated array of #NMSettingsConnection objects that were + * filtered by @func (or all connections if no filter was specified). + * The order is arbitrary. + * Caller is responsible for freeing the returned array with free(), + * the contained values do not need to be unrefed. + */ +NMSettingsConnection ** +nm_settings_get_connections_clone (NMSettings *self, + guint *out_len, + NMSettingsConnectionFilterFunc func, + gpointer func_data) +{ + NMSettingsConnection *const*list_cached; + NMSettingsConnection **list; + guint len, i, j; + + g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); + + list_cached = nm_settings_get_connections (self, &len); + +#if NM_MORE_ASSERTS + nm_assert (list_cached); + for (i = 0; i < len; i++) + nm_assert (NM_IS_SETTINGS_CONNECTION (list_cached[i])); + nm_assert (!list_cached[i]); +#endif + + list = g_new (NMSettingsConnection *, ((gsize) len + 1)); + if (func) { + for (i = 0, j = 0; i < len; i++) { + if (func (self, list_cached[i], func_data)) + list[j++] = list_cached[i]; + } + list[j] = NULL; + len = j; + } else + memcpy (list, list_cached, sizeof (list[0]) * ((gsize) len + 1)); + + NM_SET_OUT (out_len, len); + return list; +} + /* Returns a list of NMSettingsConnections. * The list is sorted in the order suitable for auto-connecting, i.e. * first go connections with autoconnect=yes and most recent timestamp. - * Caller must free the list with g_slist_free(). + * Caller must free the list with g_free(), but not the list items. */ -GSList * -nm_settings_get_connections_sorted (NMSettings *self) +NMSettingsConnection ** +nm_settings_get_connections_sorted (NMSettings *self, guint *out_len) { - GHashTableIter iter; - gpointer data = NULL; - GSList *list = NULL; + NMSettingsConnection **connections; + guint len; g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - g_hash_table_iter_init (&iter, NM_SETTINGS_GET_PRIVATE (self)->connections); - while (g_hash_table_iter_next (&iter, NULL, &data)) - list = g_slist_insert_sorted (list, data, connection_sort); - return list; + connections = nm_settings_get_connections_clone (self, &len, NULL, NULL); + if (len > 1) + g_qsort_with_data (connections, len, sizeof (NMSettingsConnection *), nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); + + NM_SET_OUT (out_len, len); + return connections; } NMSettingsConnection * @@ -2085,107 +2108,6 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quittin /*****************************************************************************/ -/* GCompareFunc helper for sorting "best" connections. - * The function sorts connections in ascending timestamp order. - * That means an older connection (lower timestamp) goes before - * a newer one. - */ -gint -nm_settings_sort_connections (gconstpointer a, gconstpointer b) -{ - NMSettingsConnection *ac = (NMSettingsConnection *) a; - NMSettingsConnection *bc = (NMSettingsConnection *) b; - guint64 ats = 0, bts = 0; - - if (ac == bc) - return 0; - if (!ac) - return -1; - if (!bc) - return 1; - - /* In the future we may use connection priorities in addition to timestamps */ - nm_settings_connection_get_timestamp (ac, &ats); - nm_settings_connection_get_timestamp (bc, &bts); - - if (ats < bts) - return -1; - else if (ats > bts) - return 1; - return 0; -} - -/** - * nm_settings_get_best_connections: - * @self: the #NMSetting - * @max_requested: if non-zero, the maximum number of connections to return - * @ctype1: an #NMSetting base type (eg NM_SETTING_WIRELESS_SETTING_NAME) to - * filter connections against - * @ctype2: a second #NMSetting base type (eg NM_SETTING_WIRELESS_SETTING_NAME) - * to filter connections against - * @func: caller-supplied function for filtering connections - * @func_data: caller-supplied data passed to @func - * - * Returns: a #GSList of #NMConnection objects in sorted order representing the - * "best" or highest-priority connections filtered by @ctype1 and/or @ctype2, - * and/or @func. Caller is responsible for freeing the returned #GSList, but - * the contained values do not need to be unreffed. - */ -GSList * -nm_settings_get_best_connections (NMSettings *self, - guint max_requested, - const char *ctype1, - const char *ctype2, - NMConnectionFilterFunc func, - gpointer func_data) -{ - NMSettingsPrivate *priv; - GSList *sorted = NULL; - GHashTableIter iter; - NMSettingsConnection *connection; - guint added = 0; - guint64 oldest = 0; - - g_return_val_if_fail (NM_IS_SETTINGS (self), NULL); - - priv = NM_SETTINGS_GET_PRIVATE (self); - - g_hash_table_iter_init (&iter, priv->connections); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &connection)) { - guint64 cur_ts = 0; - - if (ctype1 && !nm_connection_is_type (NM_CONNECTION (connection), ctype1)) - continue; - if (ctype2 && !nm_connection_is_type (NM_CONNECTION (connection), ctype2)) - continue; - if (func && !func (self, NM_CONNECTION (connection), func_data)) - continue; - - /* Don't bother with a connection that's older than the oldest one in the list */ - if (max_requested && added >= max_requested) { - nm_settings_connection_get_timestamp (connection, &cur_ts); - if (cur_ts <= oldest) - continue; - } - - /* List is sorted with oldest first */ - sorted = g_slist_insert_sorted (sorted, connection, nm_settings_sort_connections); - added++; - - if (max_requested && added > max_requested) { - /* Over the limit, remove the oldest one */ - sorted = g_slist_delete_link (sorted, sorted); - added--; - } - - nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (sorted->data), &oldest); - } - - return g_slist_reverse (sorted); -} - -/*****************************************************************************/ - gboolean nm_settings_get_startup_complete (NMSettings *self) { diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index c8a7ebae0c..0771edee13 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -57,9 +57,9 @@ * * Returns: %TRUE to allow the connection, %FALSE to ignore it */ -typedef gboolean (*NMConnectionFilterFunc) (NMSettings *settings, - NMConnection *connection, - gpointer func_data); +typedef gboolean (*NMSettingsConnectionFilterFunc) (NMSettings *settings, + NMSettingsConnection *connection, + gpointer func_data); typedef struct _NMSettingsClass NMSettingsClass; @@ -97,14 +97,13 @@ void nm_settings_add_connection_dbus (NMSettings *self, NMSettingsConnection *const* nm_settings_get_connections (NMSettings *settings, guint *out_len); -GSList *nm_settings_get_connections_sorted (NMSettings *settings); +NMSettingsConnection **nm_settings_get_connections_clone (NMSettings *self, + guint *out_len, + NMSettingsConnectionFilterFunc func, + gpointer func_data); -GSList *nm_settings_get_best_connections (NMSettings *self, - guint max_requested, - const char *ctype1, - const char *ctype2, - NMConnectionFilterFunc func, - gpointer func_data); +NMSettingsConnection **nm_settings_get_connections_sorted (NMSettings *self, + guint *out_len); NMSettingsConnection *nm_settings_add_connection (NMSettings *settings, NMConnection *connection, @@ -126,8 +125,6 @@ void nm_settings_device_added (NMSettings *self, NMDevice *device); void nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quitting); -gint nm_settings_sort_connections (gconstpointer a, gconstpointer b); - gboolean nm_settings_get_startup_complete (NMSettings *self); void nm_settings_set_transient_hostname (NMSettings *self, diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 81d8e05c1e..ef1a4f2b6a 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -870,6 +870,12 @@ _create_connection_autoconnect (const char *id, gboolean autoconnect, int autoco return c; } +static int +_cmp_autoconnect_priority_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data) +{ + return nm_utils_cmp_connection_by_autoconnect_priority (*((NMConnection **) pa), *((NMConnection **) pb)); +} + static void _test_connection_sort_autoconnect_priority_one (NMConnection **list, gboolean shuffle) { @@ -892,12 +898,12 @@ _test_connection_sort_autoconnect_priority_one (NMConnection **list, gboolean sh } /* sort it... */ - g_ptr_array_sort (connections, (GCompareFunc) nm_utils_cmp_connection_by_autoconnect_priority); + g_ptr_array_sort_with_data (connections, _cmp_autoconnect_priority_p_with_data, NULL); for (i = 0; i < count; i++) { if (list[i] == connections->pdata[i]) continue; - if (shuffle && nm_utils_cmp_connection_by_autoconnect_priority (&list[i], (NMConnection **) &connections->pdata[i]) == 0) + if (shuffle && nm_utils_cmp_connection_by_autoconnect_priority (list[i], connections->pdata[i]) == 0) continue; g_message ("After sorting, the order of connections is not as expected!! Offending index: %d", i); for (j = 0; j < count; j++) |