diff options
author | Thomas Haller <thaller@redhat.com> | 2021-07-14 15:48:37 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-07-23 17:02:04 +0200 |
commit | e6562493ef2a7d0db2565aeb74942ec29105de85 (patch) | |
tree | 785c760209bf557d626a2fafb3025fe49ecf8b73 | |
parent | ed8e098c30805d6c2f1595c82733e9976ea187e5 (diff) | |
download | NetworkManager-e6562493ef2a7d0db2565aeb74942ec29105de85.tar.gz |
libnm: add from_dbus_fcn for direct properties
There is a quest to move away from the GObject/GValue based setters.
Add _nm_setting_property_from_dbus_fcn_direct(), which can parse
the GVariant and use the direct_type to set the property.
Note that for backward compatibility, we still need
_nm_property_variant_to_gvalue() to convert alternative GVariant
types to the destination value. This means, as before, on the D-Bus
API a property of a certain type can be represented as various D-Bus
types.
-rw-r--r-- | src/libnm-core-impl/nm-setting-connection.c | 11 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-setting-private.h | 8 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-setting.c | 200 | ||||
-rw-r--r-- | src/libnm-core-impl/tests/test-setting.c | 10 | ||||
-rw-r--r-- | src/libnm-core-intern/nm-core-internal.h | 17 |
5 files changed, 227 insertions, 19 deletions
diff --git a/src/libnm-core-impl/nm-setting-connection.c b/src/libnm-core-impl/nm-setting-connection.c index 147f7209d7..6aacc31c5e 100644 --- a/src/libnm-core-impl/nm-setting-connection.c +++ b/src/libnm-core-impl/nm-setting-connection.c @@ -1894,9 +1894,9 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass) .direct_type = NM_VALUE_TYPE_STRING, .compare_fcn = compare_fcn_id, .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct, - .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop, - .from_dbus_is_full = TRUE), - + .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct, + .from_dbus_is_full = TRUE, + .from_dbus_direct_allow_transform = TRUE), NMSettingConnectionPrivate, id); @@ -2021,8 +2021,9 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass) .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct, .missing_from_dbus_fcn = nm_setting_connection_no_interface_name, - .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop, - .from_dbus_is_full = TRUE), + .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct, + .from_dbus_is_full = TRUE, + .from_dbus_direct_allow_transform = TRUE), NMSettingConnectionPrivate, interface_name); diff --git a/src/libnm-core-impl/nm-setting-private.h b/src/libnm-core-impl/nm-setting-private.h index 65a1b341a0..8ffb482a7e 100644 --- a/src/libnm-core-impl/nm-setting-private.h +++ b/src/libnm-core-impl/nm-setting-private.h @@ -391,6 +391,14 @@ _nm_setting_property_from_dbus_fcn_direct_mac_address(const NMSettInfoSetting * NMSettingParseFlags parse_flags, GError ** error); +gboolean _nm_setting_property_from_dbus_fcn_direct(const NMSettInfoSetting * sett_info, + const NMSettInfoProperty *property_info, + NMSetting * setting, + GVariant * connection_dict, + GVariant * value, + NMSettingParseFlags parse_flags, + GError ** error); + gboolean _nm_setting_property_from_dbus_fcn_gprop(const NMSettInfoSetting * sett_info, const NMSettInfoProperty *property_info, NMSetting * setting, diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c index ac98a9ae45..70370d4e51 100644 --- a/src/libnm-core-impl/nm-setting.c +++ b/src/libnm-core-impl/nm-setting.c @@ -1139,6 +1139,186 @@ _nm_setting_property_from_dbus_fcn_direct_mac_address(const NMSettInfoSetting * } gboolean +_nm_setting_property_from_dbus_fcn_direct(const NMSettInfoSetting * sett_info, + const NMSettInfoProperty *property_info, + NMSetting * setting, + GVariant * connection_dict, + GVariant * value, + NMSettingParseFlags parse_flags, + GError ** error) +{ + nm_assert(property_info->param_spec); + nm_assert(NM_FLAGS_HAS(property_info->param_spec->flags, G_PARAM_WRITABLE)); + nm_assert(!NM_FLAGS_HAS(property_info->param_spec->flags, G_PARAM_CONSTRUCT_ONLY)); + nm_assert(!property_info->property_type->typdata_from_dbus.gprop_fcn); + +#define _variant_get_value_transform(property_info, value, gtype, gvalue_get, out_val) \ + ({ \ + const NMSettInfoProperty const *_property_info = (property_info); \ + const GType _gtype = (gtype); \ + GVariant * _value = (value); \ + gboolean _success = FALSE; \ + \ + nm_assert(_property_info->param_spec->value_type == _gtype); \ + if (_property_info->property_type->from_dbus_direct_allow_transform) { \ + nm_auto_unset_gvalue GValue _gvalue = G_VALUE_INIT; \ + \ + g_value_init(&_gvalue, _gtype); \ + if (_nm_property_variant_to_gvalue(_value, &_gvalue)) { \ + *(out_val) = (gvalue_get(&_gvalue)); \ + _success = TRUE; \ + } \ + } \ + _success; \ + }) + + switch (property_info->property_type->direct_type) { + case NM_VALUE_TYPE_BOOL: + { + bool * p_val; + gboolean v; + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) + v = g_variant_get_boolean(value); + else { + if (!_variant_get_value_transform(property_info, + value, + G_TYPE_BOOLEAN, + g_value_get_boolean, + &v)) + goto out_error_wrong_dbus_type; + v = !!v; + } + + p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset); + if (*p_val == v) + goto out_unchanged; + *p_val = v; + goto out_notify; + } + case NM_VALUE_TYPE_INT32: + { + const GParamSpecInt *param_spec; + gint32 * p_val; + int v; + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) { + G_STATIC_ASSERT(sizeof(int) >= sizeof(gint32)); + v = g_variant_get_int32(value); + } else { + if (!_variant_get_value_transform(property_info, + value, + G_TYPE_INT, + g_value_get_int, + &v)) + goto out_error_wrong_dbus_type; + } + + p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset); + if (*p_val == v) + goto out_unchanged; + + param_spec = NM_G_PARAM_SPEC_CAST_INT(property_info->param_spec); + if (v < param_spec->minimum || v > param_spec->maximum) + goto out_error_param_spec_validation; + *p_val = v; + goto out_notify; + } + case NM_VALUE_TYPE_UINT32: + { + const GParamSpecUInt *param_spec; + guint32 * p_val; + guint v; + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_UINT32)) { + G_STATIC_ASSERT(sizeof(guint) >= sizeof(guint32)); + v = g_variant_get_uint32(value); + } else { + if (!_variant_get_value_transform(property_info, + value, + G_TYPE_UINT, + g_value_get_uint, + &v)) + goto out_error_wrong_dbus_type; + } + + p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset); + if (*p_val == v) + goto out_unchanged; + + param_spec = NM_G_PARAM_SPEC_CAST_UINT(property_info->param_spec); + if (v < param_spec->minimum || v > param_spec->maximum) + goto out_error_param_spec_validation; + *p_val = v; + goto out_notify; + } + case NM_VALUE_TYPE_STRING: + { + gs_free char *v_free = NULL; + char ** p_val; + const char * v; + + if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) { + v = g_variant_get_string(value, NULL); + } else { + if (!_variant_get_value_transform(property_info, + value, + G_TYPE_STRING, + g_value_dup_string, + &v_free)) + goto out_error_wrong_dbus_type; + v = v_free; + } + + p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset); + if (!_property_direct_set_string(property_info, p_val, v)) + goto out_unchanged; + + goto out_notify; + } + default: + break; + } + + nm_assert_not_reached(); + +out_unchanged: + return TRUE; + +out_notify: + g_object_notify_by_pspec(G_OBJECT(setting), property_info->param_spec); + return TRUE; + +out_error_wrong_dbus_type: + if (NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)) + return TRUE; + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("can't set property of type '%s' from value of type '%s'"), + property_info->property_type->dbus_type + ? g_variant_type_peek_string(property_info->property_type->dbus_type) + : (property_info->param_spec + ? g_type_name(property_info->param_spec->value_type) + : "(unknown)"), + g_variant_get_type_string(value)); + g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), property_info->name); + return FALSE; + +out_error_param_spec_validation: + if (NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)) + return TRUE; + g_set_error(error, + NM_UTILS_ERROR, + NM_UTILS_ERROR_UNKNOWN, + _("value of type '%s' is invalid or out of range for property '%s'"), + g_variant_get_type_string(value), + property_info->name); + g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), property_info->name); + return FALSE; +} + +gboolean _nm_setting_property_from_dbus_fcn_gprop(const NMSettInfoSetting * sett_info, const NMSettInfoProperty *property_info, NMSetting * setting, @@ -3014,32 +3194,36 @@ const NMSettInfoPropertType nm_sett_info_propert_type_direct_boolean = .direct_type = NM_VALUE_TYPE_BOOL, .compare_fcn = _nm_setting_property_compare_fcn_direct, .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct, - .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop, - .from_dbus_is_full = TRUE); + .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct, + .from_dbus_is_full = TRUE, + .from_dbus_direct_allow_transform = TRUE); const NMSettInfoPropertType nm_sett_info_propert_type_direct_int32 = NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_INT32, .direct_type = NM_VALUE_TYPE_INT32, .compare_fcn = _nm_setting_property_compare_fcn_direct, .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct, - .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop, - .from_dbus_is_full = TRUE); + .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct, + .from_dbus_is_full = TRUE, + .from_dbus_direct_allow_transform = TRUE); const NMSettInfoPropertType nm_sett_info_propert_type_direct_uint32 = NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_UINT32, .direct_type = NM_VALUE_TYPE_UINT32, .compare_fcn = _nm_setting_property_compare_fcn_direct, .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct, - .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop, - .from_dbus_is_full = TRUE); + .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct, + .from_dbus_is_full = TRUE, + .from_dbus_direct_allow_transform = TRUE); const NMSettInfoPropertType nm_sett_info_propert_type_direct_string = NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_STRING, .direct_type = NM_VALUE_TYPE_STRING, .compare_fcn = _nm_setting_property_compare_fcn_direct, .to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct, - .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop, - .from_dbus_is_full = TRUE); + .from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct, + .from_dbus_is_full = TRUE, + .from_dbus_direct_allow_transform = TRUE); const NMSettInfoPropertType nm_sett_info_propert_type_direct_mac_address = NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT( diff --git a/src/libnm-core-impl/tests/test-setting.c b/src/libnm-core-impl/tests/test-setting.c index 240918f16c..cc634c6ff5 100644 --- a/src/libnm-core-impl/tests/test-setting.c +++ b/src/libnm-core-impl/tests/test-setting.c @@ -4562,11 +4562,21 @@ check_done:; g_assert(sip->property_type->from_dbus_fcn == _nm_setting_property_from_dbus_fcn_gprop); } + if (sip->property_type->from_dbus_direct_allow_transform) { + g_assert(sip->property_type->from_dbus_fcn + == _nm_setting_property_from_dbus_fcn_direct); + } + if (sip->property_type->from_dbus_fcn == _nm_setting_property_from_dbus_fcn_direct) { + /* for the moment, all direct properties allow transformation. */ + g_assert(sip->property_type->from_dbus_direct_allow_transform); + } + if (sip->property_type->from_dbus_fcn == _nm_setting_property_from_dbus_fcn_gprop) g_assert(sip->param_spec); g_assert(sip->property_type->from_dbus_is_full == NM_IN_SET(sip->property_type->from_dbus_fcn, + _nm_setting_property_from_dbus_fcn_direct, _nm_setting_property_from_dbus_fcn_gprop, _nm_setting_property_from_dbus_fcn_ignore)); diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index b539fb1a73..4a8b9f66e7 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -701,6 +701,13 @@ typedef struct { * from_dbus_fcn() are ignored. If true, then error are propagated. */ bool from_dbus_is_full : 1; + /* Only if from_dbus_fcn is set to _nm_setting_property_from_dbus_fcn_direct. + * Historically, libnm used g_dbus_gvariant_to_gvalue() and g_value_transform() to + * convert from D-Bus to the GObject property. Thereby, various transformations are + * allowed and supported. If this is TRUE, then such transformations are still + * allowed for backward compatibility. */ + bool from_dbus_direct_allow_transform : 1; + /* compare_fcn() returns a ternary, where DEFAULT means that the property should not * be compared due to the compare @flags. A TRUE/FALSE result means that the property is * equal/not-equal. @@ -720,12 +727,10 @@ typedef struct { NMSettInfoPropMissingFromDBusFcn missing_from_dbus_fcn; struct { - union { - /* If from_dbus_fcn is set to _nm_setting_property_from_dbus_fcn_gprop, - * then this is an optional handler for converting between GVariant and - * GValue. */ - NMSettInfoPropGPropFromDBusFcn gprop_fcn; - }; + /* Only if from_dbus_fcn is set to _nm_setting_property_from_dbus_fcn_gprop. + * This is an optional handler for converting between GVariant and + * GValue. */ + NMSettInfoPropGPropFromDBusFcn gprop_fcn; } typdata_from_dbus; struct { |