diff options
Diffstat (limited to 'libnm-util/nm-connection.c')
| -rw-r--r-- | libnm-util/nm-connection.c | 730 |
1 files changed, 437 insertions, 293 deletions
diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c index 390b2a3b..b0b683bd 100644 --- a/libnm-util/nm-connection.c +++ b/libnm-util/nm-connection.c @@ -19,16 +19,16 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * (C) Copyright 2007 - 2011 Red Hat, Inc. + * (C) Copyright 2007 - 2013 Red Hat, Inc. * (C) Copyright 2007 - 2008 Novell, Inc. */ #include <glib-object.h> +#include <glib/gi18n.h> #include <dbus/dbus-glib.h> #include <string.h> #include "nm-connection.h" #include "nm-utils.h" -#include "nm-utils-private.h" #include "nm-dbus-glib-types.h" #include "nm-setting-private.h" @@ -49,6 +49,8 @@ #include "nm-setting-vpn.h" #include "nm-setting-olpc-mesh.h" #include "nm-setting-bond.h" +#include "nm-setting-team.h" +#include "nm-setting-team-port.h" #include "nm-setting-bridge.h" #include "nm-setting-bridge-port.h" #include "nm-setting-vlan.h" @@ -114,6 +116,7 @@ enum { enum { SECRETS_UPDATED, SECRETS_CLEARED, + CHANGED, LAST_SIGNAL }; @@ -121,114 +124,6 @@ static guint signals[LAST_SIGNAL] = { 0 }; /*************************************************************/ -static GHashTable *registered_settings = NULL; - -static void __attribute__((constructor)) -_ensure_registered (void) -{ - g_type_init (); - _nm_utils_register_value_transformations (); - if (G_UNLIKELY (registered_settings == NULL)) - registered_settings = g_hash_table_new (g_str_hash, g_str_equal); -} - -typedef struct { - GType type; - guint32 priority; - GQuark error_quark; -} SettingInfo; - -/* - * _nm_register_setting: - * @name: the name of the #NMSetting object to register - * @type: the #GType of the #NMSetting - * @priority: the sort priority of the setting, see below - * @error_quark: the setting's error quark - * - * INTERNAL ONLY: registers a setting's internal properties, like its priority - * and its error quark type, with libnm-util. - * - * A setting's priority should roughly follow the OSI layer model, but it also - * controls which settings get asked for secrets first. Thus settings which - * relate to things that must be working first, like hardware, should get a - * higher priority than things which layer on top of the hardware. For example, - * the GSM/CDMA settings should provide secrets before the PPP setting does, - * because a PIN is required to unlock the device before PPP can even start. - * Even settings without secrets should be assigned the right priority. - * - * 0: reserved for the Connection setting - * - * 1: hardware-related settings like Ethernet, WiFi, Infiniband, Bridge, etc. - * These priority 1 settings are also "base types", which means that at least - * one of them is required for the connection to be valid, and their name is - * valid in the 'type' property of the Connection setting. - * - * 2: hardware-related auxiliary settings that require a base setting to be - * successful first, like WiFi security, 802.1x, etc. - * - * 3: hardware-independent settings that are required before IP connectivity - * can be established, like PPP, PPPoE, etc. - * - * 4: IP-level stuff - */ -void -_nm_register_setting (const char *name, - const GType type, - const guint32 priority, - const GQuark error_quark) -{ - SettingInfo *info; - - g_return_if_fail (name != NULL); - g_return_if_fail (type != G_TYPE_INVALID); - g_return_if_fail (type != G_TYPE_NONE); - g_return_if_fail (error_quark != 0); - g_return_if_fail (priority <= 4); - - _ensure_registered (); - - if (G_LIKELY (g_hash_table_lookup (registered_settings, name))) - return; - - if (priority == 0) - g_assert_cmpstr (name, ==, NM_SETTING_CONNECTION_SETTING_NAME); - - info = g_slice_new0 (SettingInfo); - info->type = type; - info->priority = priority; - info->error_quark = error_quark; - g_hash_table_insert (registered_settings, (gpointer) name, info); -} - -static guint32 -_get_setting_priority (NMSetting *setting) -{ - GHashTableIter iter; - SettingInfo *info; - - _ensure_registered (); - - g_hash_table_iter_init (&iter, registered_settings); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &info)) { - if (G_OBJECT_TYPE (setting) == info->type) - return info->priority; - } - return G_MAXUINT32; -} - -static gboolean -_is_setting_base_type (NMSetting *setting) -{ - /* Historical oddity: PPPoE is a base-type even though it's not - * priority 1. It needs to be sorted *after* lower-level stuff like - * WiFi security or 802.1x for secrets, but it's still allowed as a - * base type. - */ - return _get_setting_priority (setting) == 1 || NM_IS_SETTING_PPPOE (setting); -} - -/*************************************************************/ - /** * nm_connection_lookup_setting_type: * @name: a setting name @@ -240,18 +135,7 @@ _is_setting_base_type (NMSetting *setting) GType nm_connection_lookup_setting_type (const char *name) { - SettingInfo *info; - - g_return_val_if_fail (name != NULL, G_TYPE_NONE); - - _ensure_registered (); - - info = g_hash_table_lookup (registered_settings, name); - if (info) - return info->type; - - g_warning ("Unknown setting '%s'", name); - return G_TYPE_INVALID; + return _nm_setting_lookup_setting_type (name); } /** @@ -266,17 +150,7 @@ nm_connection_lookup_setting_type (const char *name) GType nm_connection_lookup_setting_type_by_quark (GQuark error_quark) { - SettingInfo *info; - GHashTableIter iter; - - _ensure_registered (); - - g_hash_table_iter_init (&iter, registered_settings); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &info)) { - if (info->error_quark == error_quark) - return info->type; - } - return G_TYPE_INVALID; + return _nm_setting_lookup_setting_type_by_quark (error_quark); } /** @@ -303,17 +177,21 @@ nm_connection_create_setting (const char *name) } static void -parse_one_setting (gpointer key, gpointer value, gpointer user_data) +setting_changed_cb (NMSetting *setting, + GParamSpec *pspec, + NMConnection *self) { - NMConnection *connection = (NMConnection *) user_data; - GType type; - NMSetting *setting = NULL; + g_signal_emit (self, signals[CHANGED], 0); +} - type = nm_connection_lookup_setting_type ((char *) key); - if (type) - setting = nm_setting_new_from_hash (type, (GHashTable *) value); - if (setting) - nm_connection_add_setting (connection, setting); +static void +_nm_connection_add_setting (NMConnection *connection, NMSetting *setting) +{ + g_hash_table_insert (NM_CONNECTION_GET_PRIVATE (connection)->settings, + (gpointer) G_OBJECT_TYPE_NAME (setting), + setting); + /* Listen for property changes so we can emit the 'changed' signal */ + g_signal_connect (setting, "notify", (GCallback) setting_changed_cb, connection); } /** @@ -332,8 +210,8 @@ nm_connection_add_setting (NMConnection *connection, NMSetting *setting) g_return_if_fail (NM_IS_CONNECTION (connection)); g_return_if_fail (NM_IS_SETTING (setting)); - g_hash_table_insert (NM_CONNECTION_GET_PRIVATE (connection)->settings, - g_strdup (G_OBJECT_TYPE_NAME (setting)), setting); + _nm_connection_add_setting (connection, setting); + g_signal_emit (connection, signals[CHANGED], 0); } /** @@ -347,10 +225,21 @@ nm_connection_add_setting (NMConnection *connection, NMSetting *setting) void nm_connection_remove_setting (NMConnection *connection, GType setting_type) { + NMConnectionPrivate *priv; + NMSetting *setting; + const char *setting_name; + g_return_if_fail (NM_IS_CONNECTION (connection)); g_return_if_fail (g_type_is_a (setting_type, NM_TYPE_SETTING)); - g_hash_table_remove (NM_CONNECTION_GET_PRIVATE (connection)->settings, g_type_name (setting_type)); + priv = NM_CONNECTION_GET_PRIVATE (connection); + setting_name = g_type_name (setting_type); + setting = g_hash_table_lookup (priv->settings, setting_name); + if (setting) { + g_signal_handlers_disconnect_by_func (setting, setting_changed_cb, connection); + g_hash_table_remove (priv->settings, setting_name); + g_signal_emit (connection, signals[CHANGED], 0); + } } /** @@ -371,7 +260,7 @@ nm_connection_get_setting (NMConnection *connection, GType setting_type) g_return_val_if_fail (g_type_is_a (setting_type, NM_TYPE_SETTING), NULL); return (NMSetting *) g_hash_table_lookup (NM_CONNECTION_GET_PRIVATE (connection)->settings, - g_type_name (setting_type)); + g_type_name (setting_type)); } /** @@ -380,7 +269,7 @@ nm_connection_get_setting (NMConnection *connection, GType setting_type) * @name: a setting name * * Gets the #NMSetting with the given name, if one has been previously added - * the the #NMConnection. + * the #NMConnection. * * Returns: (transfer none): the #NMSetting, or %NULL if no setting with that name was previously * added to the #NMConnection @@ -447,6 +336,38 @@ validate_permissions_type (GHashTable *hash, GError **error) return TRUE; } +static gboolean +hash_to_connection (NMConnection *connection, GHashTable *new, GError **error) +{ + GHashTableIter iter; + const char *setting_name; + GHashTable *setting_hash; + gboolean changed, valid; + NMConnectionPrivate *priv = NM_CONNECTION_GET_PRIVATE (connection); + + if ((changed = g_hash_table_size (priv->settings) > 0)) + g_hash_table_remove_all (priv->settings); + + g_hash_table_iter_init (&iter, new); + while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) { + GType type = nm_connection_lookup_setting_type (setting_name); + + if (type) { + NMSetting *setting = nm_setting_new_from_hash (type, setting_hash); + + if (setting) { + _nm_connection_add_setting (connection, setting); + changed = TRUE; + } + } + } + + valid = nm_connection_verify (connection, error); + if (changed) + g_signal_emit (connection, signals[CHANGED], 0); + return valid; +} + /** * nm_connection_replace_settings: * @connection: a #NMConnection @@ -461,42 +382,71 @@ nm_connection_replace_settings (NMConnection *connection, GHashTable *new_settings, GError **error) { - g_return_val_if_fail (connection != NULL, FALSE); + gboolean valid = FALSE; + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); g_return_val_if_fail (new_settings != NULL, FALSE); if (error) g_return_val_if_fail (*error == NULL, FALSE); - if (!validate_permissions_type (new_settings, error)) - return FALSE; + if (validate_permissions_type (new_settings, error)) + valid = hash_to_connection (connection, new_settings, error); + return valid; +} - g_hash_table_remove_all (NM_CONNECTION_GET_PRIVATE (connection)->settings); - g_hash_table_foreach (new_settings, parse_one_setting, connection); +/** + * nm_connection_replace_settings_from_connection: + * @connection: a #NMConnection + * @new_connection: a #NMConnection to replace the settings of @connection with + * @error: location to store error, or %NULL + * + * Deep-copies the settings of @new_conenction and replaces the settings of @connection + * with the copied settings. + * + * Returns: %TRUE if the settings were valid and added to the connection, %FALSE + * if they were not + * + * Since: 0.9.10 + **/ +gboolean +nm_connection_replace_settings_from_connection (NMConnection *connection, + NMConnection *new_connection, + GError **error) +{ + NMConnectionPrivate *priv; + GHashTableIter iter; + NMSetting *setting; + gboolean changed, valid; - return nm_connection_verify (connection, error); -} + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (new_connection), FALSE); + if (error) + g_return_val_if_fail (*error == NULL, FALSE); -typedef struct { - NMConnection *other; - gboolean failed; - NMSettingCompareFlags flags; -} CompareConnectionInfo; + /* When 'connection' and 'new_connection' are the same object simply return + * in order not to destroy 'connection' */ + if (connection == new_connection) + return TRUE; -static void -compare_one_setting (gpointer key, gpointer value, gpointer user_data) -{ - NMSetting *setting = (NMSetting *) value; - CompareConnectionInfo *info = (CompareConnectionInfo *) user_data; - NMSetting *other_setting; + /* No need to validate permissions like nm_connection_replace_settings() + * since we're dealing with an NMConnection which has already done that. + */ - if (info->failed) - return; + priv = NM_CONNECTION_GET_PRIVATE (connection); + if ((changed = g_hash_table_size (priv->settings) > 0)) + g_hash_table_remove_all (priv->settings); + + if (g_hash_table_size (NM_CONNECTION_GET_PRIVATE (new_connection)->settings)) { + g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (new_connection)->settings); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) + _nm_connection_add_setting (connection, nm_setting_duplicate (setting)); + changed = TRUE; + } - other_setting = nm_connection_get_setting (info->other, G_OBJECT_TYPE (setting)); - if (other_setting) - info->failed = nm_setting_compare (setting, other_setting, info->flags) ? FALSE : TRUE; - else - info->failed = TRUE; + valid = nm_connection_verify (connection, error); + if (changed) + g_signal_emit (connection, signals[CHANGED], 0); + return valid; } /** @@ -516,28 +466,29 @@ nm_connection_compare (NMConnection *a, NMConnection *b, NMSettingCompareFlags flags) { - NMConnectionPrivate *priv; - CompareConnectionInfo info = { b, FALSE, flags }; + GHashTableIter iter; + NMSetting *src; - if (!a && !b) + if (a == b) return TRUE; - if (!a || !b) return FALSE; - priv = NM_CONNECTION_GET_PRIVATE (a); - g_hash_table_foreach (priv->settings, compare_one_setting, &info); - if (info.failed == FALSE) { - /* compare A to B, then if that is the same compare B to A to ensure - * that keys that are in B but not A will make the comparison fail. - */ - info.failed = FALSE; - info.other = a; - priv = NM_CONNECTION_GET_PRIVATE (b); - g_hash_table_foreach (priv->settings, compare_one_setting, &info); + /* B / A: ensure settings in B that are not in A make the comparison fail */ + if (g_hash_table_size (NM_CONNECTION_GET_PRIVATE (a)->settings) != + g_hash_table_size (NM_CONNECTION_GET_PRIVATE (b)->settings)) + return FALSE; + + /* A / B: ensure all settings in A match corresponding ones in B */ + g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (a)->settings); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &src)) { + NMSetting *cmp = nm_connection_get_setting (b, G_OBJECT_TYPE (src)); + + if (!cmp || !nm_setting_compare (src, cmp, flags)) + return FALSE; } - return info.failed ? FALSE : TRUE; + return TRUE; } @@ -600,7 +551,6 @@ nm_connection_diff (NMConnection *a, { GHashTable *diffs; - g_return_val_if_fail (a != NULL, FALSE); g_return_val_if_fail (NM_IS_CONNECTION (a), FALSE); g_return_val_if_fail (out_settings != NULL, FALSE); g_return_val_if_fail (*out_settings == NULL, FALSE); @@ -632,7 +582,7 @@ nm_connection_diff (NMConnection *a, * * Validates the connection and all its settings. Each setting's properties * have allowed values, and some values are dependent on other values. For - * example, if a WiFi connection is security enabled, the #NMSettingWireless + * example, if a Wi-Fi connection is security enabled, the #NMSettingWireless * setting object's 'security' property must contain the setting name of the * #NMSettingWirelessSecurity object, which must also be present in the * connection for the connection to be valid. As another example, the @@ -712,7 +662,7 @@ nm_connection_verify (NMConnection *connection, GError **error) return FALSE; } - if (!_is_setting_base_type (base)) { + if (!_nm_setting_is_base_type (base)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID, @@ -749,73 +699,113 @@ nm_connection_update_secrets (NMConnection *connection, GError **error) { NMSetting *setting; - gboolean success; - GHashTable *tmp; + gboolean success = TRUE, updated = FALSE; + GHashTable *setting_hash = NULL; + GHashTableIter iter; + const char *key; + gboolean hashed_connection = FALSE; + int success_detail; - g_return_val_if_fail (connection != NULL, FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); g_return_val_if_fail (secrets != NULL, FALSE); if (error) g_return_val_if_fail (*error == NULL, FALSE); + /* Empty @secrets means success */ + if (g_hash_table_size (secrets) == 0) + return TRUE; + + /* For backwards compatibility, this function accepts either a hashed + * connection (GHashTable of GHashTables of GValues) or a single hashed + * setting (GHashTable of GValues). + */ + g_hash_table_iter_init (&iter, secrets); + while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL)) { + if (_nm_setting_lookup_setting_type (key) != G_TYPE_INVALID) { + /* @secrets looks like a hashed connection */ + hashed_connection = TRUE; + break; + } + } + if (setting_name) { - /* Update just one setting */ + /* Update just one setting's secrets */ setting = nm_connection_get_setting_by_name (connection, setting_name); if (!setting) { g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_SETTING_NOT_FOUND, - setting_name); + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + setting_name); return FALSE; } - /* Check if this is a hash of hashes, ie a full deserialized connection, - * not just a single hashed setting. - */ - tmp = g_hash_table_lookup (secrets, setting_name); - success = nm_setting_update_secrets (setting, tmp ? tmp : secrets, error); - } else { - GHashTableIter iter; - const char *name; + if (hashed_connection) { + setting_hash = g_hash_table_lookup (secrets, setting_name); + if (!setting_hash) { + /* The hashed connection that didn't contain any secrets for + * @setting_name; just return success. + */ + return TRUE; + } + } - success = TRUE; /* Just in case 'secrets' has no elements */ + g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection); + success_detail = _nm_setting_update_secrets (setting, + setting_hash ? setting_hash : secrets, + error); + g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection); + + if (success_detail == NM_SETTING_UPDATE_SECRET_ERROR) + return FALSE; + if (success_detail == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED) + updated = TRUE; + } else { + if (!hashed_connection) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + key); + return FALSE; + } - /* Try as a serialized connection (GHashTable of GHashTables) */ + /* check first, whether all the settings exist... */ g_hash_table_iter_init (&iter, secrets); - while (g_hash_table_iter_next (&iter, (gpointer) &name, (gpointer) &tmp)) { - setting = nm_connection_get_setting_by_name (connection, name); + while (g_hash_table_iter_next (&iter, (gpointer) &key, NULL)) { + setting = nm_connection_get_setting_by_name (connection, key); if (!setting) { g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_SETTING_NOT_FOUND, - name); + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + key); return FALSE; } + } + /* Update each setting with any secrets from the hashed connection */ + g_hash_table_iter_init (&iter, secrets); + while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &setting_hash)) { /* Update the secrets for this setting */ - success = nm_setting_update_secrets (setting, tmp, error); - if (success == FALSE) + setting = nm_connection_get_setting_by_name (connection, key); + + g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection); + success_detail = _nm_setting_update_secrets (setting, setting_hash, error); + g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection); + + if (success_detail == NM_SETTING_UPDATE_SECRET_ERROR) { + success = FALSE; break; + } + if (success_detail == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED) + updated = TRUE; } } - if (success) - g_signal_emit (connection, signals[SECRETS_UPDATED], 0, setting_name); - return success; -} -static gint -setting_priority_compare (gconstpointer a, gconstpointer b) -{ - guint32 prio_a, prio_b; - - prio_a = _get_setting_priority (NM_SETTING (a)); - prio_b = _get_setting_priority (NM_SETTING (b)); + if (updated) { + g_signal_emit (connection, signals[SECRETS_UPDATED], 0, setting_name); + g_signal_emit (connection, signals[CHANGED], 0); + } - if (prio_a < prio_b) - return -1; - else if (prio_a == prio_b) - return 0; - return 1; + return success; } /** @@ -848,7 +838,6 @@ nm_connection_need_secrets (NMConnection *connection, const char *name = NULL; NMSetting *setting; - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); if (hints) g_return_val_if_fail (*hints == NULL, NULL); @@ -858,7 +847,7 @@ nm_connection_need_secrets (NMConnection *connection, /* Get list of settings in priority order */ g_hash_table_iter_init (&hiter, priv->settings); while (g_hash_table_iter_next (&hiter, NULL, (gpointer) &setting)) - settings = g_slist_insert_sorted (settings, setting, setting_priority_compare); + settings = g_slist_insert_sorted (settings, setting, _nm_setting_compare_priority); for (iter = settings; iter; iter = g_slist_next (iter)) { GPtrArray *secrets; @@ -892,14 +881,20 @@ nm_connection_clear_secrets (NMConnection *connection) { GHashTableIter iter; NMSetting *setting; + gboolean changed = FALSE; g_return_if_fail (NM_IS_CONNECTION (connection)); g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) - nm_setting_clear_secrets (setting); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) { + g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection); + changed |= _nm_setting_clear_secrets (setting); + g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection); + } g_signal_emit (connection, signals[SECRETS_CLEARED], 0); + if (changed) + g_signal_emit (connection, signals[CHANGED], 0); } /** @@ -918,14 +913,20 @@ nm_connection_clear_secrets_with_flags (NMConnection *connection, { GHashTableIter iter; NMSetting *setting; + gboolean changed = FALSE; g_return_if_fail (NM_IS_CONNECTION (connection)); g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) - nm_setting_clear_secrets_with_flags (setting, func, user_data); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) { + g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection); + changed |= _nm_setting_clear_secrets_with_flags (setting, func, user_data); + g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection); + } g_signal_emit (connection, signals[SECRETS_CLEARED], 0); + if (changed) + g_signal_emit (connection, signals[CHANGED], 0); } /** @@ -953,7 +954,6 @@ nm_connection_to_hash (NMConnection *connection, NMSettingHashFlags flags) gpointer key, data; GHashTable *ret, *setting_hash; - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); ret = g_hash_table_new_full (g_str_hash, g_str_equal, @@ -987,7 +987,7 @@ nm_connection_to_hash (NMConnection *connection, NMSettingHashFlags flags) * %NM_SETTING_WIRELESS_SETTING_NAME or %NM_SETTING_WIRED_SETTING_NAME) * * A convenience function to check if the given @connection is a particular - * type (ie wired, wifi, ppp, etc). Checks the #NMSettingConnection:type + * type (ie wired, Wi-Fi, ppp, etc). Checks the #NMSettingConnection:type * property of the connection and matches that against @type. * * Returns: %TRUE if the connection is of the given @type, %FALSE if not @@ -998,12 +998,12 @@ nm_connection_is_type (NMConnection *connection, const char *type) NMSettingConnection *s_con; const char *type2; - g_return_val_if_fail (connection != NULL, FALSE); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); g_return_val_if_fail (type != NULL, FALSE); s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); + if (!s_con) + return FALSE; type2 = nm_setting_connection_get_connection_type (s_con); @@ -1035,16 +1035,6 @@ nm_connection_for_each_setting_value (NMConnection *connection, nm_setting_enumerate_values (NM_SETTING (value), func, user_data); } -static void -dump_setting (gpointer key, gpointer value, gpointer user_data) -{ - char *str; - - str = nm_setting_to_string (NM_SETTING (value)); - g_print ("%s\n", str); - g_free (str); -} - /** * nm_connection_dump: * @connection: the #NMConnection @@ -1056,9 +1046,20 @@ dump_setting (gpointer key, gpointer value, gpointer user_data) void nm_connection_dump (NMConnection *connection) { - g_return_if_fail (NM_IS_CONNECTION (connection)); + GHashTableIter iter; + NMSetting *setting; + const char *setting_name; + char *str; + + if (!connection) + return; - g_hash_table_foreach (NM_CONNECTION_GET_PRIVATE (connection)->settings, dump_setting, NULL); + g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings); + while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting)) { + str = nm_setting_to_string (setting); + g_print ("%s\n", str); + g_free (str); + } } /** @@ -1165,22 +1166,13 @@ nm_connection_new_from_hash (GHashTable *hash, GError **error) return NULL; connection = nm_connection_new (); - g_hash_table_foreach (hash, parse_one_setting, connection); - - if (!nm_connection_verify (connection, error)) { + if (!hash_to_connection (connection, hash, error)) { g_object_unref (connection); return NULL; } - return connection; } -static void -duplicate_cb (gpointer key, gpointer value, gpointer user_data) -{ - nm_connection_add_setting (NM_CONNECTION (user_data), nm_setting_duplicate (NM_SETTING (value))); -} - /** * nm_connection_duplicate: * @connection: the #NMConnection to duplicate @@ -1194,12 +1186,17 @@ NMConnection * nm_connection_duplicate (NMConnection *connection) { NMConnection *dup; + GHashTableIter iter; + NMSetting *setting; g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); dup = nm_connection_new (); nm_connection_set_path (dup, nm_connection_get_path (connection)); - g_hash_table_foreach (NM_CONNECTION_GET_PRIVATE (connection)->settings, duplicate_cb, dup); + + g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) + nm_connection_add_setting (dup, nm_setting_duplicate (setting)); return dup; } @@ -1217,7 +1214,6 @@ nm_connection_get_uuid (NMConnection *connection) { NMSettingConnection *s_con; - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); s_con = nm_connection_get_setting_connection (connection); @@ -1239,7 +1235,6 @@ nm_connection_get_id (NMConnection *connection) { NMSettingConnection *s_con; - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); s_con = nm_connection_get_setting_connection (connection); @@ -1248,6 +1243,72 @@ nm_connection_get_id (NMConnection *connection) return nm_setting_connection_get_id (s_con); } +/** + * nm_connection_get_connection_type: + * @connection: the #NMConnection + * + * A shortcut to return the type from the connection's #NMSettingConnection. + * + * Returns: the type from the connection's 'connection' setting + * + * Since: 0.9.10 + **/ +const char * +nm_connection_get_connection_type (NMConnection *connection) +{ + NMSettingConnection *s_con; + + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + s_con = nm_connection_get_setting_connection (connection); + g_return_val_if_fail (s_con != NULL, NULL); + + return nm_setting_connection_get_connection_type (s_con); +} + +/** + * nm_connection_get_virtual_device_description: + * @connection: an #NMConnection for a virtual device type + * + * Returns the name that nm_device_disambiguate_names() would + * return for the virtual device that would be created for @connection. + * Eg, "VLAN (eth1.1)". + * + * Returns: (transfer full): the name of @connection's device, + * or %NULL if @connection is not a virtual connection type + * + * Since: 0.9.10 + */ +char * +nm_connection_get_virtual_device_description (NMConnection *connection) +{ + const char *iface, *type, *display_type; + NMSettingConnection *s_con; + + iface = nm_connection_get_virtual_iface_name (connection); + if (!iface) + return NULL; + + s_con = nm_connection_get_setting_connection (connection); + g_return_val_if_fail (s_con != NULL, NULL); + type = nm_setting_connection_get_connection_type (s_con); + + if (!strcmp (type, NM_SETTING_BOND_SETTING_NAME)) + display_type = _("Bond"); + else if (!strcmp (type, NM_SETTING_TEAM_SETTING_NAME)) + display_type = _("Team"); + else if (!strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME)) + display_type = _("Bridge"); + else if (!strcmp (type, NM_SETTING_VLAN_SETTING_NAME)) + display_type = _("VLAN"); + else { + g_warning ("Unrecognized virtual device type '%s'", type); + display_type = type; + } + + return g_strdup_printf ("%s (%s)", display_type, iface); +} + /*************************************************************/ /** @@ -1261,7 +1322,6 @@ nm_connection_get_id (NMConnection *connection) NMSetting8021x * nm_connection_get_setting_802_1x (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSetting8021x *) nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); @@ -1278,7 +1338,6 @@ nm_connection_get_setting_802_1x (NMConnection *connection) NMSettingBluetooth * nm_connection_get_setting_bluetooth (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH); @@ -1295,13 +1354,48 @@ nm_connection_get_setting_bluetooth (NMConnection *connection) NMSettingBond * nm_connection_get_setting_bond (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingBond *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BOND); } /** + * nm_connection_get_setting_team: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingTeam the connection might contain. + * + * Returns: (transfer none): an #NMSettingTeam if the connection contains one, otherwise %NULL + * + * Since: 0.9.10 + **/ +NMSettingTeam * +nm_connection_get_setting_team (NMConnection *connection) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + return (NMSettingTeam *) nm_connection_get_setting (connection, NM_TYPE_SETTING_TEAM); +} + +/** + * nm_connection_get_setting_team_port: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingTeamPort the connection might contain. + * + * Returns: (transfer none): an #NMSettingTeamPort if the connection contains one, otherwise %NULL + * + * Since: 0.9.10 + **/ +NMSettingTeamPort * +nm_connection_get_setting_team_port (NMConnection *connection) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + return (NMSettingTeamPort *) nm_connection_get_setting (connection, NM_TYPE_SETTING_TEAM_PORT); +} + +/** * nm_connection_get_setting_bridge: * @connection: the #NMConnection * @@ -1312,7 +1406,6 @@ nm_connection_get_setting_bond (NMConnection *connection) NMSettingBridge * nm_connection_get_setting_bridge (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingBridge *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BRIDGE); @@ -1329,7 +1422,6 @@ nm_connection_get_setting_bridge (NMConnection *connection) NMSettingCdma * nm_connection_get_setting_cdma (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingCdma *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CDMA); @@ -1346,13 +1438,48 @@ nm_connection_get_setting_cdma (NMConnection *connection) NMSettingConnection * nm_connection_get_setting_connection (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); } /** + * nm_connection_get_setting_dcb: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingDcb the connection might contain. + * + * Returns: (transfer none): an #NMSettingDcb if the connection contains one, otherwise NULL + * + * Since: 0.9.10 + **/ +NMSettingDcb * +nm_connection_get_setting_dcb (NMConnection *connection) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + return (NMSettingDcb *) nm_connection_get_setting (connection, NM_TYPE_SETTING_DCB); +} + +/** + * nm_connection_get_setting_generic: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingGeneric the connection might contain. + * + * Returns: (transfer none): an #NMSettingGeneric if the connection contains one, otherwise NULL + * + * Since: 0.9.10 + **/ +NMSettingGeneric * +nm_connection_get_setting_generic (NMConnection *connection) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + return (NMSettingGeneric *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GENERIC); +} + +/** * nm_connection_get_setting_gsm: * @connection: the #NMConnection * @@ -1363,7 +1490,6 @@ nm_connection_get_setting_connection (NMConnection *connection) NMSettingGsm * nm_connection_get_setting_gsm (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingGsm *) nm_connection_get_setting (connection, NM_TYPE_SETTING_GSM); @@ -1380,7 +1506,6 @@ nm_connection_get_setting_gsm (NMConnection *connection) NMSettingInfiniband * nm_connection_get_setting_infiniband (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingInfiniband *) nm_connection_get_setting (connection, NM_TYPE_SETTING_INFINIBAND); @@ -1397,7 +1522,6 @@ nm_connection_get_setting_infiniband (NMConnection *connection) NMSettingIP4Config * nm_connection_get_setting_ip4_config (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingIP4Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP4_CONFIG); @@ -1414,7 +1538,6 @@ nm_connection_get_setting_ip4_config (NMConnection *connection) NMSettingIP6Config * nm_connection_get_setting_ip6_config (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingIP6Config *) nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG); @@ -1431,7 +1554,6 @@ nm_connection_get_setting_ip6_config (NMConnection *connection) NMSettingOlpcMesh * nm_connection_get_setting_olpc_mesh (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingOlpcMesh *) nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH); @@ -1448,7 +1570,6 @@ nm_connection_get_setting_olpc_mesh (NMConnection *connection) NMSettingPPP * nm_connection_get_setting_ppp (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingPPP *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPP); @@ -1465,7 +1586,6 @@ nm_connection_get_setting_ppp (NMConnection *connection) NMSettingPPPOE * nm_connection_get_setting_pppoe (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingPPPOE *) nm_connection_get_setting (connection, NM_TYPE_SETTING_PPPOE); @@ -1482,7 +1602,6 @@ nm_connection_get_setting_pppoe (NMConnection *connection) NMSettingSerial * nm_connection_get_setting_serial (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingSerial *) nm_connection_get_setting (connection, NM_TYPE_SETTING_SERIAL); @@ -1499,7 +1618,6 @@ nm_connection_get_setting_serial (NMConnection *connection) NMSettingVPN * nm_connection_get_setting_vpn (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN); @@ -1516,7 +1634,6 @@ nm_connection_get_setting_vpn (NMConnection *connection) NMSettingWimax * nm_connection_get_setting_wimax (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingWimax *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIMAX); @@ -1533,7 +1650,6 @@ nm_connection_get_setting_wimax (NMConnection *connection) NMSettingWired * nm_connection_get_setting_wired (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingWired *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRED); @@ -1550,7 +1666,6 @@ nm_connection_get_setting_wired (NMConnection *connection) NMSettingAdsl * nm_connection_get_setting_adsl (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingAdsl *) nm_connection_get_setting (connection, NM_TYPE_SETTING_ADSL); @@ -1567,7 +1682,6 @@ nm_connection_get_setting_adsl (NMConnection *connection) NMSettingWireless * nm_connection_get_setting_wireless (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingWireless *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS); @@ -1584,7 +1698,6 @@ nm_connection_get_setting_wireless (NMConnection *connection) NMSettingWirelessSecurity * nm_connection_get_setting_wireless_security (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingWirelessSecurity *) nm_connection_get_setting (connection, NM_TYPE_SETTING_WIRELESS_SECURITY); @@ -1601,7 +1714,6 @@ nm_connection_get_setting_wireless_security (NMConnection *connection) NMSettingBridgePort * nm_connection_get_setting_bridge_port (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingBridgePort *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BRIDGE_PORT); @@ -1618,7 +1730,6 @@ nm_connection_get_setting_bridge_port (NMConnection *connection) NMSettingVlan * nm_connection_get_setting_vlan (NMConnection *connection) { - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); return (NMSettingVlan *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VLAN); @@ -1631,7 +1742,24 @@ nm_connection_init (NMConnection *connection) { NMConnectionPrivate *priv = NM_CONNECTION_GET_PRIVATE (connection); - priv->settings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + priv->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); +} + +static void +dispose (GObject *object) +{ + NMConnection *self = NM_CONNECTION (object); + NMConnectionPrivate *priv = NM_CONNECTION_GET_PRIVATE (self); + GHashTableIter iter; + NMSetting *setting; + + g_hash_table_iter_init (&iter, priv->settings); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) { + g_signal_handlers_disconnect_by_func (setting, setting_changed_cb, self); + g_hash_table_iter_remove (&iter); + } + + G_OBJECT_CLASS (nm_connection_parent_class)->dispose (object); } static void @@ -1641,10 +1769,7 @@ finalize (GObject *object) NMConnectionPrivate *priv = NM_CONNECTION_GET_PRIVATE (connection); g_hash_table_destroy (priv->settings); - priv->settings = NULL; - g_free (priv->path); - priv->path = NULL; G_OBJECT_CLASS (nm_connection_parent_class)->finalize (object); } @@ -1691,6 +1816,7 @@ nm_connection_class_init (NMConnectionClass *klass) /* virtual methods */ object_class->set_property = set_property; object_class->get_property = get_property; + object_class->dispose = dispose; object_class->finalize = finalize; /* Properties */ @@ -1721,7 +1847,7 @@ nm_connection_class_init (NMConnectionClass *klass) * have been changed. */ signals[SECRETS_UPDATED] = - g_signal_new ("secrets-updated", + g_signal_new (NM_CONNECTION_SECRETS_UPDATED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMConnectionClass, secrets_updated), @@ -1738,7 +1864,25 @@ nm_connection_class_init (NMConnectionClass *klass) * are cleared. */ signals[SECRETS_CLEARED] = - g_signal_new ("secrets-cleared", + g_signal_new (NM_CONNECTION_SECRETS_CLEARED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + /** + * NMConnection::changed: + * @connection: the object on which the signal is emitted + * + * The ::changed signal is emitted when any property of any property + * (including secrets) of any setting of the connection is modified, + * or when settings are added or removed. + * + * Since: 0.9.10 + */ + signals[CHANGED] = + g_signal_new (NM_CONNECTION_CHANGED, G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, |