summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-02-10 14:43:34 +0100
committerThomas Haller <thaller@redhat.com>2017-02-10 14:43:35 +0100
commitf549307ca5f7a6bf3e925497472616c87c8d4cbe (patch)
tree6c191b03e2a63f2c20ed076db79f022ac8f5dcd2
parentf3504c9bc214aa32f7a498a1adb48b840be8809a (diff)
parentef6c393889551cdcf46c7db3a7d881817d0866e6 (diff)
downloadNetworkManager-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.c43
-rw-r--r--src/nm-checkpoint.c10
-rw-r--r--src/nm-core-utils.c64
-rw-r--r--src/nm-core-utils.h2
-rw-r--r--src/nm-manager.c109
-rw-r--r--src/nm-manager.h5
-rw-r--r--src/nm-policy.c110
-rw-r--r--src/settings/nm-settings-connection.c90
-rw-r--r--src/settings/nm-settings-connection.h5
-rw-r--r--src/settings/nm-settings.c212
-rw-r--r--src/settings/nm-settings.h21
-rw-r--r--src/tests/test-general.c10
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++)