summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@gnome.org>2014-07-29 18:25:10 -0400
committerDan Winship <danw@gnome.org>2014-09-03 11:08:14 -0400
commite49ee6f9a31ea3a3fc3893291e1f7392df328943 (patch)
treef16ed37dcc1a8b2a33baa0abd74f9d9086b1c142
parentbf1309641440ca790ff5b0f0b8a270550990fca8 (diff)
downloadNetworkManager-e49ee6f9a31ea3a3fc3893291e1f7392df328943.tar.gz
libnm-core: add dbus-only properties to NMSettingClass
Add _nm_setting_class_add_dbus_only_property(), for declaring properties that appear in the D-Bus serialization, but which don't correspond to GObject properties. Since some property overrides will require examining settings other than the setting that they are on (eg, the value of 802-11-wireless.security depends on whether an NMSettingWirelessSecurity setting is present, and NMSettingConnection:interface-name might sometimes be set from, eg, bond.interface-name), we also update _nm_setting_to_dbus() to take the full NMConnection as an argument, and _nm_setting_new_from_dbus() to take the full connection hash. Additionally, with some deprecated properties, we'll want to validate them on construction, but we don't need to keep the value around after that. So allow _nm_setting_new_from_dbus() to return a verification error directly, so we don't need to store the value until the verify() call.
-rw-r--r--libnm-core/nm-connection.c2
-rw-r--r--libnm-core/nm-setting-private.h21
-rw-r--r--libnm-core/nm-setting.c300
-rw-r--r--libnm-core/nm-simple-connection.c4
-rw-r--r--libnm-core/tests/test-general.c10
5 files changed, 285 insertions, 52 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c
index 4e72f35927..db9c699dc7 100644
--- a/libnm-core/nm-connection.c
+++ b/libnm-core/nm-connection.c
@@ -1268,7 +1268,7 @@ nm_connection_to_dbus (NMConnection *connection, NMConnectionSerializationFlags
while (g_hash_table_iter_next (&iter, &key, &data)) {
NMSetting *setting = NM_SETTING (data);
- setting_hash = _nm_setting_to_dbus (setting, flags);
+ setting_hash = _nm_setting_to_dbus (setting, connection, flags);
if (setting_hash)
g_hash_table_insert (ret, g_strdup (nm_setting_get_name (setting)), setting_hash);
}
diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h
index de9628e7b1..05a3ae3afe 100644
--- a/libnm-core/nm-setting-private.h
+++ b/libnm-core/nm-setting-private.h
@@ -116,9 +116,28 @@ gboolean _nm_setting_slave_type_is_valid (const char *slave_type, const char **o
const char * _nm_setting_slave_type_detect_from_settings (GSList *all_settings, NMSetting **out_s_port);
GHashTable *_nm_setting_to_dbus (NMSetting *setting,
+ NMConnection *connection,
NMConnectionSerializationFlags flags);
NMSetting *_nm_setting_new_from_dbus (GType setting_type,
- GHashTable *hash);
+ GHashTable *setting_hash,
+ GHashTable *connection_hash,
+ GError **error);
+
+typedef gboolean (*NMSettingPropertyGetFunc) (NMSetting *setting,
+ NMConnection *connection,
+ const char *property,
+ GValue *value);
+typedef gboolean (*NMSettingPropertySetFunc) (NMSetting *setting,
+ GHashTable *connection_hash,
+ const char *property,
+ const GValue *value,
+ GError **error);
+
+void _nm_setting_class_add_dbus_only_property (NMSettingClass *setting_class,
+ const char *property_name,
+ GType dbus_type,
+ NMSettingPropertyGetFunc get_func,
+ NMSettingPropertySetFunc set_func);
#endif /* NM_SETTING_PRIVATE_H */
diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c
index 748a65557e..30dab04f51 100644
--- a/libnm-core/nm-setting.c
+++ b/libnm-core/nm-setting.c
@@ -372,18 +372,193 @@ _nm_setting_slave_type_detect_from_settings (GSList *all_settings, NMSetting **o
/*************************************************************/
+typedef struct {
+ const char *name;
+ GParamSpec *param_spec;
+ GType dbus_type;
+ NMSettingPropertyGetFunc get_func;
+ NMSettingPropertySetFunc set_func;
+} NMSettingProperty;
+
+static GQuark setting_property_overrides_quark;
+static GQuark setting_properties_quark;
+
+static NMSettingProperty *
+find_property (GArray *properties, const char *name)
+{
+ NMSettingProperty *property;
+ int i;
+
+ if (!properties)
+ return NULL;
+
+ for (i = 0; i < properties->len; i++) {
+ property = &g_array_index (properties, NMSettingProperty, i);
+ if (strcmp (name, property->name) == 0)
+ return property;
+ }
+
+ return NULL;
+}
+
+static void
+add_property_override (NMSettingClass *setting_class,
+ const char *property_name,
+ GType dbus_type,
+ NMSettingPropertyGetFunc get_func,
+ NMSettingPropertySetFunc set_func)
+{
+ GType setting_type = G_TYPE_FROM_CLASS (setting_class);
+ GArray *overrides;
+ NMSettingProperty override;
+
+ g_return_if_fail (g_type_get_qdata (setting_type, setting_properties_quark) == NULL);
+
+ memset (&override, 0, sizeof (override));
+ override.name = property_name;
+ override.dbus_type = dbus_type;
+ override.get_func = get_func;
+ override.set_func = set_func;
+
+ overrides = g_type_get_qdata (setting_type, setting_property_overrides_quark);
+ if (!overrides) {
+ overrides = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty));
+ g_type_set_qdata (setting_type, setting_property_overrides_quark, overrides);
+ }
+ g_return_if_fail (find_property (overrides, property_name) == NULL);
+
+ g_array_append_val (overrides, override);
+}
+
+/**
+ * _nm_setting_class_add_dbus_only_property:
+ * @setting_class: the setting class
+ * @property_name: the name of the property to override
+ * @dbus_type: the type of the property
+ * @get_func: (allow-none): function to call to get the value of the property
+ * @set_func: (allow-none): function to call to set the value of the property
+ *
+ * Registers a property named @property_name, which will be used in the D-Bus
+ * serialization of objects of @setting_class, but which does not correspond to
+ * a #GObject property.
+ *
+ * When serializing a setting to D-Bus, @get_func will be called to get the
+ * property's value. If it returns %TRUE, the value will be added to the hash,
+ * and if %FALSE, it will not. (If @get_func is %NULL, the property will always
+ * be omitted in the serialization.)
+ *
+ * When deserializing a D-Bus representation into a setting, if @property_name
+ * is present, then @set_func will be called to set (and/or verify) it. If it
+ * returns %TRUE, the value is considered to have been successfully set; if it
+ * returns %FALSE then the deserializing operation as a whole will fail with the
+ * returned #GError. (If @set_func is %NULL then the property will be ignored
+ * when deserializing.)
+ */
+void
+_nm_setting_class_add_dbus_only_property (NMSettingClass *setting_class,
+ const char *property_name,
+ GType dbus_type,
+ NMSettingPropertyGetFunc get_func,
+ NMSettingPropertySetFunc set_func)
+{
+ g_return_if_fail (NM_IS_SETTING_CLASS (setting_class));
+ g_return_if_fail (property_name != NULL);
+
+ /* Must not match any GObject property. */
+ g_return_if_fail (!g_object_class_find_property (G_OBJECT_CLASS (setting_class), property_name));
+
+ add_property_override (setting_class,
+ property_name, dbus_type,
+ get_func, set_func);
+}
+
+static GArray *
+nm_setting_class_ensure_properties (NMSettingClass *setting_class)
+{
+ GType type = G_TYPE_FROM_CLASS (setting_class), otype;
+ NMSettingProperty property, *override;
+ GArray *overrides, *type_overrides, *properties;
+ GParamSpec **property_specs;
+ guint n_property_specs, i;
+
+ properties = g_type_get_qdata (type, setting_properties_quark);
+ if (properties)
+ return properties;
+
+ /* Build overrides array from @setting_class and its superclasses */
+ overrides = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty));
+ for (otype = type; otype != G_TYPE_OBJECT; otype = g_type_parent (otype)) {
+ type_overrides = g_type_get_qdata (otype, setting_property_overrides_quark);
+ if (type_overrides)
+ g_array_append_vals (overrides, (NMSettingProperty *)type_overrides->data, type_overrides->len);
+ }
+
+ /* Build the properties array from the GParamSpecs, obeying overrides */
+ properties = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty));
+
+ property_specs = g_object_class_list_properties (G_OBJECT_CLASS (setting_class),
+ &n_property_specs);
+ for (i = 0; i < n_property_specs; i++) {
+ override = find_property (overrides, property_specs[i]->name);
+ if (override)
+ property = *override;
+ else {
+ memset (&property, 0, sizeof (property));
+ property.name = property_specs[i]->name;
+ property.param_spec = property_specs[i];
+ }
+ g_array_append_val (properties, property);
+ }
+ g_free (property_specs);
+
+ /* Add any remaining overrides not corresponding to GObject properties */
+ for (i = 0; i < overrides->len; i++) {
+ override = &g_array_index (overrides, NMSettingProperty, i);
+ if (!g_object_class_find_property (G_OBJECT_CLASS (setting_class), override->name))
+ g_array_append_val (properties, *override);
+ }
+ g_array_unref (overrides);
+
+ g_type_set_qdata (type, setting_properties_quark, properties);
+ return properties;
+}
+
+static const NMSettingProperty *
+nm_setting_class_get_properties (NMSettingClass *setting_class, guint *n_properties)
+{
+ GArray *properties;
+
+ properties = nm_setting_class_ensure_properties (setting_class);
+
+ *n_properties = properties->len;
+ return (NMSettingProperty *) properties->data;
+}
+
+static const NMSettingProperty *
+nm_setting_class_find_property (NMSettingClass *setting_class, const char *property_name)
+{
+ GArray *properties;
+
+ properties = nm_setting_class_ensure_properties (setting_class);
+ return find_property (properties, property_name);
+}
+
+/*************************************************************/
+
static void
destroy_gvalue (gpointer data)
{
GValue *value = (GValue *) data;
- g_value_unset (value);
+ if (G_IS_VALUE (value))
+ g_value_unset (value);
g_slice_free (GValue, value);
}
/**
* _nm_setting_to_dbus:
* @setting: the #NMSetting
+ * @connection: the #NMConnection containing @setting
* @flags: hash flags, e.g. %NM_CONNECTION_SERIALIZE_ALL
*
* Converts the #NMSetting into a #GHashTable mapping each setting property
@@ -394,47 +569,59 @@ destroy_gvalue (gpointer data)
* describing the setting's properties
**/
GHashTable *
-_nm_setting_to_dbus (NMSetting *setting, NMConnectionSerializationFlags flags)
+_nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionSerializationFlags flags)
{
GHashTable *hash;
- GParamSpec **property_specs;
- guint n_property_specs;
- guint i;
+ const NMSettingProperty *properties;
+ guint n_properties, i;
g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
- property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
+ properties = nm_setting_class_get_properties (NM_SETTING_GET_CLASS (setting), &n_properties);
hash = g_hash_table_new_full (g_str_hash, g_str_equal,
(GDestroyNotify) g_free, destroy_gvalue);
- for (i = 0; i < n_property_specs; i++) {
- GParamSpec *prop_spec = property_specs[i];
+ for (i = 0; i < n_properties; i++) {
+ const NMSettingProperty *property = &properties[i];
+ GParamSpec *prop_spec = property->param_spec;
GValue *value;
+ gboolean set;
+
+ if (!prop_spec && !property->get_func) {
+ /* Override property with no get_func, so we skip it. */
+ continue;
+ }
- /* 'name' doesn't get serialized */
- if (strcmp (g_param_spec_get_name (prop_spec), NM_SETTING_NAME) == 0)
+ if (prop_spec && !(prop_spec->flags & G_PARAM_WRITABLE))
continue;
if ( (flags & NM_CONNECTION_SERIALIZE_NO_SECRETS)
- && (prop_spec->flags & NM_SETTING_PARAM_SECRET))
+ && (prop_spec && (prop_spec->flags & NM_SETTING_PARAM_SECRET)))
continue;
if ( (flags & NM_CONNECTION_SERIALIZE_ONLY_SECRETS)
- && !(prop_spec->flags & NM_SETTING_PARAM_SECRET))
+ && !(prop_spec && (prop_spec->flags & NM_SETTING_PARAM_SECRET)))
continue;
value = g_slice_new0 (GValue);
- g_value_init (value, prop_spec->value_type);
- g_object_get_property (G_OBJECT (setting), prop_spec->name, value);
+ if (property->get_func) {
+ g_value_init (value, property->dbus_type);
+ set = property->get_func (setting, connection, property->name, value);
+ } else if (prop_spec) {
+ g_value_init (value, prop_spec->value_type);
+ g_object_get_property (G_OBJECT (setting), prop_spec->name, value);
+
+ /* Don't serialize values with default values */
+ set = !g_param_value_defaults (prop_spec, value);
+ } else
+ g_assert_not_reached ();
- /* Don't serialize values with default values */
- if (!g_param_value_defaults (prop_spec, value))
- g_hash_table_insert (hash, g_strdup (prop_spec->name), value);
+ if (set)
+ g_hash_table_insert (hash, g_strdup (property->name), value);
else
destroy_gvalue (value);
}
- g_free (property_specs);
/* Don't return empty hashes, except for base types */
if (g_hash_table_size (hash) < 1 && !_nm_setting_is_base_type (setting)) {
@@ -448,8 +635,11 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnectionSerializationFlags flags)
/**
* _nm_setting_new_from_dbus:
* @setting_type: the #NMSetting type which the hash contains properties for
- * @hash: (element-type utf8 GObject.Value): the #GHashTable containing a
- * string to GValue mapping of properties that apply to the setting
+ * @setting_hash: (element-type utf8 GObject.Value): the #GHashTable containing a
+ * string to #GValue mapping of properties that apply to the setting
+ * @connection_hash: (element-type utf8 GObject.Value): the #GHashTable containing a
+ * string to #GHashTable mapping of properties for the whole connection
+ * @error: location to store error, or %NULL
*
* Creates a new #NMSetting object and populates that object with the properties
* contained in the hash table, using each hash key as the property to set,
@@ -462,18 +652,21 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnectionSerializationFlags flags)
* hash table, or %NULL on failure
**/
NMSetting *
-_nm_setting_new_from_dbus (GType setting_type, GHashTable *hash)
+_nm_setting_new_from_dbus (GType setting_type,
+ GHashTable *setting_hash,
+ GHashTable *connection_hash,
+ GError **error)
{
NMSetting *setting;
- GObjectClass *class;
+ NMSettingClass *class;
GHashTableIter iter;
const char *prop_name;
- GParamSpec **property_specs;
- guint n_property_specs;
+ const NMSettingProperty *properties;
+ guint n_properties;
guint i;
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (setting_type), NULL);
- g_return_val_if_fail (hash != NULL, NULL);
+ g_return_val_if_fail (setting_hash != NULL, NULL);
/* g_type_class_ref() ensures the setting class is created if it hasn't
* already been used.
@@ -481,9 +674,9 @@ _nm_setting_new_from_dbus (GType setting_type, GHashTable *hash)
class = g_type_class_ref (setting_type);
/* Check for invalid properties first. */
- g_hash_table_iter_init (&iter, hash);
+ g_hash_table_iter_init (&iter, setting_hash);
while (g_hash_table_iter_next (&iter, (gpointer) &prop_name, NULL)) {
- if (!g_object_class_find_property (class, prop_name)) {
+ if (!nm_setting_class_find_property (class, prop_name)) {
/* Oh, we're so nice and only warn, maybe it should be a fatal error? */
g_warning ("Ignoring invalid property '%s'", prop_name);
continue;
@@ -493,22 +686,32 @@ _nm_setting_new_from_dbus (GType setting_type, GHashTable *hash)
/* Now build the setting object from the legitimate properties */
setting = (NMSetting *) g_object_new (setting_type, NULL);
- property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting), &n_property_specs);
- for (i = 0; i < n_property_specs; i++) {
- GParamSpec *prop_spec = property_specs[i];
- GValue *value;
+ properties = nm_setting_class_get_properties (class, &n_properties);
+ for (i = 0; i < n_properties; i++) {
+ const NMSettingProperty *property = &properties[i];
+ GValue *value = g_hash_table_lookup (setting_hash, property->name);
- /* 'name' doesn't get deserialized */
- if (strcmp (prop_spec->name, NM_SETTING_NAME) == 0)
- continue;
-
- value = g_hash_table_lookup (hash, prop_spec->name);
if (!value)
continue;
- g_object_set_property (G_OBJECT (setting), prop_spec->name, value);
+ if (property->set_func) {
+ if (!property->set_func (setting,
+ connection_hash,
+ property->name,
+ value,
+ error)) {
+ g_object_unref (setting);
+ setting = NULL;
+ break;
+ }
+ } else if (property->param_spec) {
+ if (!(property->param_spec->flags & G_PARAM_WRITABLE))
+ continue;
+
+ g_object_set_property (G_OBJECT (setting), property->param_spec->name, value);
+ }
}
- g_free (property_specs);
+
g_type_class_unref (class);
return setting;
@@ -1065,10 +1268,11 @@ nm_setting_need_secrets (NMSetting *setting)
static int
update_one_secret (NMSetting *setting, const char *key, GValue *value, GError **error)
{
+ const NMSettingProperty *property;
GParamSpec *prop_spec;
- prop_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), key);
- if (!prop_spec) {
+ property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), key);
+ if (!property) {
g_set_error (error,
NM_SETTING_ERROR,
NM_SETTING_ERROR_PROPERTY_NOT_FOUND,
@@ -1077,7 +1281,8 @@ update_one_secret (NMSetting *setting, const char *key, GValue *value, GError **
}
/* Silently ignore non-secrets */
- if (!(prop_spec->flags & NM_SETTING_PARAM_SECRET))
+ prop_spec = property->param_spec;
+ if (!prop_spec || !(prop_spec->flags & NM_SETTING_PARAM_SECRET))
return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
if (g_value_type_compatible (G_VALUE_TYPE (value), G_PARAM_SPEC_VALUE_TYPE (prop_spec))) {
@@ -1154,10 +1359,11 @@ _nm_setting_update_secrets (NMSetting *setting, GHashTable *secrets, GError **er
static gboolean
is_secret_prop (NMSetting *setting, const char *secret_name, GError **error)
{
+ const NMSettingProperty *property;
GParamSpec *pspec;
- pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), secret_name);
- if (!pspec) {
+ property = nm_setting_class_find_property (NM_SETTING_GET_CLASS (setting), secret_name);
+ if (!property) {
g_set_error (error,
NM_SETTING_ERROR,
NM_SETTING_ERROR_PROPERTY_NOT_FOUND,
@@ -1165,7 +1371,8 @@ is_secret_prop (NMSetting *setting, const char *secret_name, GError **error)
return FALSE;
}
- if (!(pspec->flags & NM_SETTING_PARAM_SECRET)) {
+ pspec = property->param_spec;
+ if (!pspec || !(pspec->flags & NM_SETTING_PARAM_SECRET)) {
g_set_error (error,
NM_SETTING_ERROR,
NM_SETTING_ERROR_PROPERTY_NOT_SECRET,
@@ -1507,6 +1714,11 @@ nm_setting_class_init (NMSettingClass *setting_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
+ if (!setting_property_overrides_quark)
+ setting_property_overrides_quark = g_quark_from_static_string ("nm-setting-property-overrides");
+ if (!setting_properties_quark)
+ setting_properties_quark = g_quark_from_static_string ("nm-setting-properties");
+
g_type_class_add_private (setting_class, sizeof (NMSettingPrivate));
/* virtual methods */
diff --git a/libnm-core/nm-simple-connection.c b/libnm-core/nm-simple-connection.c
index febacdc54c..0512cfbbef 100644
--- a/libnm-core/nm-simple-connection.c
+++ b/libnm-core/nm-simple-connection.c
@@ -88,7 +88,9 @@ nm_simple_connection_new_from_dbus (GHashTable *hash, GError **error)
goto failed;
}
- setting = _nm_setting_new_from_dbus (type, setting_hash);
+ setting = _nm_setting_new_from_dbus (type, setting_hash, hash, error);
+ if (!setting)
+ goto failed;
nm_connection_add_setting (connection, setting);
}
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index f5f6b403f9..797edd7526 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -680,7 +680,7 @@ test_setting_to_dbus_all (void)
s_wsec = make_test_wsec_setting ("setting-to-dbus-all");
- hash = _nm_setting_to_dbus (NM_SETTING (s_wsec), NM_CONNECTION_SERIALIZE_ALL);
+ hash = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_ALL);
/* Make sure all keys are there */
ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT),
@@ -704,7 +704,7 @@ test_setting_to_dbus_no_secrets (void)
s_wsec = make_test_wsec_setting ("setting-to-dbus-no-secrets");
- hash = _nm_setting_to_dbus (NM_SETTING (s_wsec), NM_CONNECTION_SERIALIZE_NO_SECRETS);
+ hash = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_NO_SECRETS);
/* Make sure non-secret keys are there */
ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT),
@@ -730,7 +730,7 @@ test_setting_to_dbus_only_secrets (void)
s_wsec = make_test_wsec_setting ("setting-to-dbus-only-secrets");
- hash = _nm_setting_to_dbus (NM_SETTING (s_wsec), NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
+ hash = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_ONLY_SECRETS);
/* Make sure non-secret keys are there */
ASSERT (g_hash_table_lookup (hash, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT) == NULL,
@@ -778,10 +778,10 @@ test_setting_new_from_dbus (void)
GHashTable *hash;
s_wsec = make_test_wsec_setting ("setting-to-dbus-all");
- hash = _nm_setting_to_dbus (NM_SETTING (s_wsec), NM_CONNECTION_SERIALIZE_ALL);
+ hash = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_ALL);
g_object_unref (s_wsec);
- s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, hash);
+ s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, hash, NULL, NULL);
g_hash_table_destroy (hash);
g_assert (s_wsec);