summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-07-14 15:48:37 +0200
committerThomas Haller <thaller@redhat.com>2021-07-23 17:02:04 +0200
commite6562493ef2a7d0db2565aeb74942ec29105de85 (patch)
tree785c760209bf557d626a2fafb3025fe49ecf8b73
parented8e098c30805d6c2f1595c82733e9976ea187e5 (diff)
downloadNetworkManager-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.c11
-rw-r--r--src/libnm-core-impl/nm-setting-private.h8
-rw-r--r--src/libnm-core-impl/nm-setting.c200
-rw-r--r--src/libnm-core-impl/tests/test-setting.c10
-rw-r--r--src/libnm-core-intern/nm-core-internal.h17
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 {