2020-12-23 22:21:36 +01:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2014-07-24 08:53:33 -04:00
|
|
|
/*
|
2019-10-01 09:20:35 +02:00
|
|
|
* Copyright (C) 2007 - 2011 Red Hat, Inc.
|
|
|
|
|
* Copyright (C) 2007 - 2008 Novell, Inc.
|
2014-07-24 08:53:33 -04:00
|
|
|
*/
|
|
|
|
|
|
2021-02-12 15:01:09 +01:00
|
|
|
#include "libnm-core-impl/nm-default-libnm-core.h"
|
2016-02-19 14:57:48 +01:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
#include "nm-setting.h"
|
2016-02-12 14:44:52 +01:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
#include "nm-setting-private.h"
|
|
|
|
|
#include "nm-utils.h"
|
2021-02-12 15:01:09 +01:00
|
|
|
#include "libnm-core-intern/nm-core-internal.h"
|
2014-07-24 08:53:33 -04:00
|
|
|
#include "nm-utils-private.h"
|
2014-07-29 09:22:07 -04:00
|
|
|
#include "nm-property-compare.h"
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* SECTION:nm-setting
|
|
|
|
|
* @short_description: Describes related configuration information
|
|
|
|
|
*
|
|
|
|
|
* Each #NMSetting contains properties that describe configuration that applies
|
|
|
|
|
* to a specific network layer (like IPv4 or IPv6 configuration) or device type
|
|
|
|
|
* (like Ethernet, or Wi-Fi). A collection of individual settings together
|
|
|
|
|
* make up an #NMConnection. Each property is strongly typed and usually has
|
|
|
|
|
* a number of allowed values. See each #NMSetting subclass for a description
|
|
|
|
|
* of properties and allowed values.
|
|
|
|
|
*/
|
|
|
|
|
|
2018-06-24 17:06:28 +02:00
|
|
|
/*****************************************************************************/
|
2014-07-24 08:53:33 -04:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
typedef struct {
|
|
|
|
|
GHashTable * hash;
|
|
|
|
|
const char **names;
|
|
|
|
|
GVariant ** values;
|
|
|
|
|
} GenData;
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
typedef struct {
|
|
|
|
|
const char * name;
|
|
|
|
|
GType type;
|
2017-06-01 13:43:52 +02:00
|
|
|
NMSettingPriority priority;
|
2014-07-24 08:53:33 -04:00
|
|
|
} SettingInfo;
|
|
|
|
|
|
2019-01-20 13:49:08 +01:00
|
|
|
NM_GOBJECT_PROPERTIES_DEFINE(NMSetting, PROP_NAME, );
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2018-06-24 17:06:28 +02:00
|
|
|
typedef struct {
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
GenData *gendata;
|
2018-06-24 17:06:28 +02:00
|
|
|
} NMSettingPrivate;
|
|
|
|
|
|
2018-06-24 17:41:02 +02:00
|
|
|
G_DEFINE_ABSTRACT_TYPE(NMSetting, nm_setting, G_TYPE_OBJECT)
|
2018-06-24 17:06:28 +02:00
|
|
|
|
|
|
|
|
#define NM_SETTING_GET_PRIVATE(o) \
|
|
|
|
|
(G_TYPE_INSTANCE_GET_PRIVATE((o), NM_TYPE_SETTING, NMSettingPrivate))
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-07-24 08:53:33 -04:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
static GenData *_gendata_hash(NMSetting *setting, gboolean create_if_necessary);
|
2021-06-30 00:05:49 +02:00
|
|
|
static gboolean set_property_from_dbus(const NMSettInfoProperty *property_info,
|
|
|
|
|
GVariant * src_value,
|
|
|
|
|
GValue * dst_value);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-06-01 13:43:52 +02:00
|
|
|
NMSettingPriority
|
2014-02-25 20:30:27 +01:00
|
|
|
_nm_setting_get_setting_priority(NMSetting *setting)
|
|
|
|
|
{
|
libnm: use NMMetaSettingInfo for tracking setting priority
Previously, each (non abstract) NMSetting class had to register
its name and priority via _nm_register_setting().
Note, that libnm-core.la already links against "nm-meta-setting.c",
which also redundantly keeps track of the settings name and gtype
as well.
Re-use NMMetaSettingInfo also in libnm-core.la, to track this meta
data.
The goal is to get rid of private data structures that track
meta data about NMSetting classes. In this case, "registered_settings"
hash. Instead, we should have one place where all this meta data
is tracked. This was, it is also accessible as internal API,
which can be useful (for keyfile).
Note that NMSettingClass has some overlap with NMMetaSettingInfo.
One difference is, that NMMetaSettingInfo is const, while NMSettingClass
is only initialized during the class_init() method. Appart from that,
it's mostly a matter of taste, whether we attach meta data to
NMSettingClass, to NMMetaSettingInfo, or to a static-array indexed
by NMMetaSettingType.
Note, that previously, _nm_register_setting() was private API. That
means, no user could subclass a functioning NMSetting instance. The same
is still true: NMMetaSettingInfo is internal API and users cannot access
it to create their own NMSetting subclasses. But that is almost desired.
libnm is not designed, to be extensible via subclassing, nor is it
clear why that would be a useful thing to do. One day, we should remove
the NMSetting and NMSettingClass definitions from public headers. Their
only use is subclassing the types, which however does not work.
While libnm-core was linking already against nm-meta-setting.c,
nm_meta_setting_infos was unreferenced. So, this change increases
the binary size of libnm and NetworkManager (1032 bytes). Note however
that roughly the same information was previously allocated at runtime.
2018-07-27 14:08:14 +02:00
|
|
|
const NMMetaSettingInfo *setting_info;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NM_SETTING_PRIORITY_INVALID);
|
2014-02-25 20:30:27 +01:00
|
|
|
|
libnm: use NMMetaSettingInfo for tracking setting priority
Previously, each (non abstract) NMSetting class had to register
its name and priority via _nm_register_setting().
Note, that libnm-core.la already links against "nm-meta-setting.c",
which also redundantly keeps track of the settings name and gtype
as well.
Re-use NMMetaSettingInfo also in libnm-core.la, to track this meta
data.
The goal is to get rid of private data structures that track
meta data about NMSetting classes. In this case, "registered_settings"
hash. Instead, we should have one place where all this meta data
is tracked. This was, it is also accessible as internal API,
which can be useful (for keyfile).
Note that NMSettingClass has some overlap with NMMetaSettingInfo.
One difference is, that NMMetaSettingInfo is const, while NMSettingClass
is only initialized during the class_init() method. Appart from that,
it's mostly a matter of taste, whether we attach meta data to
NMSettingClass, to NMMetaSettingInfo, or to a static-array indexed
by NMMetaSettingType.
Note, that previously, _nm_register_setting() was private API. That
means, no user could subclass a functioning NMSetting instance. The same
is still true: NMMetaSettingInfo is internal API and users cannot access
it to create their own NMSetting subclasses. But that is almost desired.
libnm is not designed, to be extensible via subclassing, nor is it
clear why that would be a useful thing to do. One day, we should remove
the NMSetting and NMSettingClass definitions from public headers. Their
only use is subclassing the types, which however does not work.
While libnm-core was linking already against nm-meta-setting.c,
nm_meta_setting_infos was unreferenced. So, this change increases
the binary size of libnm and NetworkManager (1032 bytes). Note however
that roughly the same information was previously allocated at runtime.
2018-07-27 14:08:14 +02:00
|
|
|
setting_info = NM_SETTING_GET_CLASS(setting)->setting_info;
|
|
|
|
|
return setting_info ? setting_info->setting_priority : NM_SETTING_PRIORITY_INVALID;
|
2014-02-25 20:30:27 +01:00
|
|
|
}
|
|
|
|
|
|
2017-06-01 13:43:52 +02:00
|
|
|
NMSettingPriority
|
2017-05-22 20:31:00 +02:00
|
|
|
_nm_setting_get_base_type_priority(NMSetting *setting)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
libnm: use NMMetaSettingInfo for tracking setting priority
Previously, each (non abstract) NMSetting class had to register
its name and priority via _nm_register_setting().
Note, that libnm-core.la already links against "nm-meta-setting.c",
which also redundantly keeps track of the settings name and gtype
as well.
Re-use NMMetaSettingInfo also in libnm-core.la, to track this meta
data.
The goal is to get rid of private data structures that track
meta data about NMSetting classes. In this case, "registered_settings"
hash. Instead, we should have one place where all this meta data
is tracked. This was, it is also accessible as internal API,
which can be useful (for keyfile).
Note that NMSettingClass has some overlap with NMMetaSettingInfo.
One difference is, that NMMetaSettingInfo is const, while NMSettingClass
is only initialized during the class_init() method. Appart from that,
it's mostly a matter of taste, whether we attach meta data to
NMSettingClass, to NMMetaSettingInfo, or to a static-array indexed
by NMMetaSettingType.
Note, that previously, _nm_register_setting() was private API. That
means, no user could subclass a functioning NMSetting instance. The same
is still true: NMMetaSettingInfo is internal API and users cannot access
it to create their own NMSetting subclasses. But that is almost desired.
libnm is not designed, to be extensible via subclassing, nor is it
clear why that would be a useful thing to do. One day, we should remove
the NMSetting and NMSettingClass definitions from public headers. Their
only use is subclassing the types, which however does not work.
While libnm-core was linking already against nm-meta-setting.c,
nm_meta_setting_infos was unreferenced. So, this change increases
the binary size of libnm and NetworkManager (1032 bytes). Note however
that roughly the same information was previously allocated at runtime.
2018-07-27 14:08:14 +02:00
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NM_SETTING_PRIORITY_INVALID);
|
|
|
|
|
|
2020-11-16 09:50:27 +01:00
|
|
|
return nm_meta_setting_info_get_base_type_priority(NM_SETTING_GET_CLASS(setting)->setting_info,
|
|
|
|
|
G_OBJECT_TYPE(setting));
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2014-08-12 17:25:26 -04:00
|
|
|
/**
|
|
|
|
|
* nm_setting_lookup_type:
|
|
|
|
|
* @name: a setting name
|
|
|
|
|
*
|
|
|
|
|
* Returns the #GType of the setting's class for a given setting name.
|
|
|
|
|
*
|
2014-08-22 10:20:29 -04:00
|
|
|
* Returns: the #GType of the setting's class, or %G_TYPE_INVALID if
|
|
|
|
|
* @name is not recognized.
|
2014-08-12 17:25:26 -04:00
|
|
|
**/
|
2014-07-24 08:53:33 -04:00
|
|
|
GType
|
2014-08-12 17:25:26 -04:00
|
|
|
nm_setting_lookup_type(const char *name)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
libnm: use NMMetaSettingInfo for tracking setting priority
Previously, each (non abstract) NMSetting class had to register
its name and priority via _nm_register_setting().
Note, that libnm-core.la already links against "nm-meta-setting.c",
which also redundantly keeps track of the settings name and gtype
as well.
Re-use NMMetaSettingInfo also in libnm-core.la, to track this meta
data.
The goal is to get rid of private data structures that track
meta data about NMSetting classes. In this case, "registered_settings"
hash. Instead, we should have one place where all this meta data
is tracked. This was, it is also accessible as internal API,
which can be useful (for keyfile).
Note that NMSettingClass has some overlap with NMMetaSettingInfo.
One difference is, that NMMetaSettingInfo is const, while NMSettingClass
is only initialized during the class_init() method. Appart from that,
it's mostly a matter of taste, whether we attach meta data to
NMSettingClass, to NMMetaSettingInfo, or to a static-array indexed
by NMMetaSettingType.
Note, that previously, _nm_register_setting() was private API. That
means, no user could subclass a functioning NMSetting instance. The same
is still true: NMMetaSettingInfo is internal API and users cannot access
it to create their own NMSetting subclasses. But that is almost desired.
libnm is not designed, to be extensible via subclassing, nor is it
clear why that would be a useful thing to do. One day, we should remove
the NMSetting and NMSettingClass definitions from public headers. Their
only use is subclassing the types, which however does not work.
While libnm-core was linking already against nm-meta-setting.c,
nm_meta_setting_infos was unreferenced. So, this change increases
the binary size of libnm and NetworkManager (1032 bytes). Note however
that roughly the same information was previously allocated at runtime.
2018-07-27 14:08:14 +02:00
|
|
|
const NMMetaSettingInfo *setting_info;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2017-06-01 21:06:17 +02:00
|
|
|
g_return_val_if_fail(name, G_TYPE_INVALID);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
libnm: use NMMetaSettingInfo for tracking setting priority
Previously, each (non abstract) NMSetting class had to register
its name and priority via _nm_register_setting().
Note, that libnm-core.la already links against "nm-meta-setting.c",
which also redundantly keeps track of the settings name and gtype
as well.
Re-use NMMetaSettingInfo also in libnm-core.la, to track this meta
data.
The goal is to get rid of private data structures that track
meta data about NMSetting classes. In this case, "registered_settings"
hash. Instead, we should have one place where all this meta data
is tracked. This was, it is also accessible as internal API,
which can be useful (for keyfile).
Note that NMSettingClass has some overlap with NMMetaSettingInfo.
One difference is, that NMMetaSettingInfo is const, while NMSettingClass
is only initialized during the class_init() method. Appart from that,
it's mostly a matter of taste, whether we attach meta data to
NMSettingClass, to NMMetaSettingInfo, or to a static-array indexed
by NMMetaSettingType.
Note, that previously, _nm_register_setting() was private API. That
means, no user could subclass a functioning NMSetting instance. The same
is still true: NMMetaSettingInfo is internal API and users cannot access
it to create their own NMSetting subclasses. But that is almost desired.
libnm is not designed, to be extensible via subclassing, nor is it
clear why that would be a useful thing to do. One day, we should remove
the NMSetting and NMSettingClass definitions from public headers. Their
only use is subclassing the types, which however does not work.
While libnm-core was linking already against nm-meta-setting.c,
nm_meta_setting_infos was unreferenced. So, this change increases
the binary size of libnm and NetworkManager (1032 bytes). Note however
that roughly the same information was previously allocated at runtime.
2018-07-27 14:08:14 +02:00
|
|
|
setting_info = nm_meta_setting_infos_by_name(name);
|
|
|
|
|
return setting_info ? setting_info->get_setting_gtype() : G_TYPE_INVALID;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
int
|
2014-07-24 08:53:33 -04:00
|
|
|
_nm_setting_compare_priority(gconstpointer a, gconstpointer b)
|
|
|
|
|
{
|
2017-06-01 13:43:52 +02:00
|
|
|
NMSettingPriority prio_a, prio_b;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2014-02-25 20:30:27 +01:00
|
|
|
prio_a = _nm_setting_get_setting_priority((NMSetting *) a);
|
|
|
|
|
prio_b = _nm_setting_get_setting_priority((NMSetting *) b);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
if (prio_a < prio_b)
|
|
|
|
|
return -1;
|
|
|
|
|
else if (prio_a == prio_b)
|
|
|
|
|
return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2014-07-07 17:05:10 +02:00
|
|
|
gboolean
|
|
|
|
|
_nm_setting_slave_type_is_valid(const char *slave_type, const char **out_port_type)
|
|
|
|
|
{
|
|
|
|
|
const char *port_type = NULL;
|
|
|
|
|
gboolean found = TRUE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-07 17:05:10 +02:00
|
|
|
if (!slave_type)
|
|
|
|
|
found = FALSE;
|
2019-12-05 10:13:34 +01:00
|
|
|
else if (NM_IN_STRSET(slave_type, NM_SETTING_BOND_SETTING_NAME, NM_SETTING_VRF_SETTING_NAME)) {
|
|
|
|
|
/* pass */
|
|
|
|
|
} else if (nm_streq(slave_type, NM_SETTING_BRIDGE_SETTING_NAME))
|
2014-07-07 17:05:10 +02:00
|
|
|
port_type = NM_SETTING_BRIDGE_PORT_SETTING_NAME;
|
2019-12-05 10:13:34 +01:00
|
|
|
else if (nm_streq(slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME))
|
2017-08-01 18:36:34 +02:00
|
|
|
port_type = NM_SETTING_OVS_PORT_SETTING_NAME;
|
2019-12-05 10:13:34 +01:00
|
|
|
else if (nm_streq(slave_type, NM_SETTING_OVS_PORT_SETTING_NAME))
|
2017-10-02 09:03:19 +02:00
|
|
|
port_type = NM_SETTING_OVS_INTERFACE_SETTING_NAME;
|
2019-12-05 10:13:34 +01:00
|
|
|
else if (nm_streq(slave_type, NM_SETTING_TEAM_SETTING_NAME))
|
2014-07-07 17:05:10 +02:00
|
|
|
port_type = NM_SETTING_TEAM_PORT_SETTING_NAME;
|
|
|
|
|
else
|
|
|
|
|
found = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-07 17:05:10 +02:00
|
|
|
if (out_port_type)
|
|
|
|
|
*out_port_type = port_type;
|
|
|
|
|
return found;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-07-07 17:05:10 +02:00
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
static const NMSettInfoProperty *
|
|
|
|
|
_nm_sett_info_property_find_in_array(const NMSettInfoProperty *properties,
|
|
|
|
|
guint len,
|
|
|
|
|
const char * name)
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
{
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
guint i;
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
|
if (nm_streq(name, properties[i].name))
|
|
|
|
|
return &properties[i];
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-22 15:23:41 +02:00
|
|
|
gboolean
|
2019-09-22 15:32:04 +02:00
|
|
|
_nm_properties_override_assert(const NMSettInfoProperty *prop_info)
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
{
|
2021-06-17 22:01:34 +02:00
|
|
|
#if NM_MORE_ASSERTS
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
nm_assert(prop_info);
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
nm_assert((!!prop_info->name) != (!!prop_info->param_spec));
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
nm_assert(!prop_info->param_spec || !prop_info->name
|
|
|
|
|
|| nm_streq0(prop_info->name, prop_info->param_spec->name));
|
|
|
|
|
|
2021-06-17 22:01:34 +02:00
|
|
|
if (prop_info->property_type) {
|
|
|
|
|
const NMSettInfoPropertType *property_type = prop_info->property_type;
|
2019-04-24 16:28:11 +02:00
|
|
|
|
2021-06-17 22:01:34 +02:00
|
|
|
/* we always require a dbus_type. */
|
|
|
|
|
nm_assert(property_type->dbus_type);
|
2019-04-24 16:28:11 +02:00
|
|
|
|
2021-06-30 00:05:49 +02:00
|
|
|
if (property_type->typdata_from_dbus.gprop_fcn)
|
|
|
|
|
nm_assert(property_type->from_dbus_fcn == _nm_setting_property_from_dbus_fcn_gprop);
|
|
|
|
|
|
|
|
|
|
if (property_type->from_dbus_fcn == _nm_setting_property_from_dbus_fcn_gprop)
|
|
|
|
|
nm_assert(prop_info->param_spec);
|
2014-07-29 18:25:10 -04:00
|
|
|
|
2021-06-17 22:01:34 +02:00
|
|
|
if (!prop_info->param_spec) {
|
2021-06-30 00:05:49 +02:00
|
|
|
/* if we don't have a param_spec, we cannot have typdata_from_dbus.gprop_fcn. */
|
|
|
|
|
nm_assert(property_type->from_dbus_fcn || !property_type->typdata_from_dbus.gprop_fcn);
|
2021-06-17 22:01:34 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2019-09-22 15:23:41 +02:00
|
|
|
return TRUE;
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
}
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
static NMSettInfoSetting _sett_info_settings[_NM_META_SETTING_TYPE_NUM];
|
|
|
|
|
|
2019-09-21 20:35:18 +02:00
|
|
|
const NMSettInfoSetting *
|
|
|
|
|
nmtst_sett_info_settings(void)
|
|
|
|
|
{
|
|
|
|
|
return _sett_info_settings;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 15:37:39 +01:00
|
|
|
static int
|
|
|
|
|
_property_infos_sort_cmp_setting_connection(gconstpointer p_a,
|
|
|
|
|
gconstpointer p_b,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoProperty *a = *((const NMSettInfoProperty *const *) p_a);
|
|
|
|
|
const NMSettInfoProperty *b = *((const NMSettInfoProperty *const *) p_b);
|
|
|
|
|
int c_name;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-04 15:37:39 +01:00
|
|
|
c_name = strcmp(a->name, b->name);
|
|
|
|
|
nm_assert(c_name != 0);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-04 15:37:39 +01:00
|
|
|
#define CMP_AND_RETURN(n_a, n_b, name) \
|
|
|
|
|
G_STMT_START \
|
|
|
|
|
{ \
|
|
|
|
|
gboolean _is = nm_streq(n_a, "" name); \
|
|
|
|
|
\
|
|
|
|
|
if (_is || nm_streq(n_b, "" name)) \
|
|
|
|
|
return _is ? -1 : 1; \
|
|
|
|
|
} \
|
|
|
|
|
G_STMT_END
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-04 15:37:39 +01:00
|
|
|
/* for [connection], report first id, uuid, type in that order. */
|
|
|
|
|
if (c_name != 0) {
|
|
|
|
|
CMP_AND_RETURN(a->name, b->name, NM_SETTING_CONNECTION_ID);
|
|
|
|
|
CMP_AND_RETURN(a->name, b->name, NM_SETTING_CONNECTION_UUID);
|
|
|
|
|
CMP_AND_RETURN(a->name, b->name, NM_SETTING_CONNECTION_TYPE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#undef CMP_AND_RETURN
|
|
|
|
|
|
|
|
|
|
return c_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const NMSettInfoProperty *const *
|
|
|
|
|
_property_infos_sort(const NMSettInfoProperty *property_infos,
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 property_infos_len,
|
2019-01-04 15:37:39 +01:00
|
|
|
NMSettingClass * setting_class)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoProperty **arr;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 i;
|
2019-01-04 15:37:39 +01:00
|
|
|
|
|
|
|
|
#if NM_MORE_ASSERTS > 5
|
|
|
|
|
/* assert that the property names are all unique and sorted. */
|
|
|
|
|
for (i = 0; i < property_infos_len; i++) {
|
|
|
|
|
if (property_infos[i].param_spec)
|
|
|
|
|
nm_assert(nm_streq(property_infos[i].name, property_infos[i].param_spec->name));
|
|
|
|
|
if (i > 0)
|
|
|
|
|
nm_assert(strcmp(property_infos[i - 1].name, property_infos[i].name) < 0);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (property_infos_len <= 1)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (G_TYPE_FROM_CLASS(setting_class) != NM_TYPE_SETTING_CONNECTION) {
|
|
|
|
|
/* we only do something special for certain setting types. This one,
|
|
|
|
|
* has just alphabetical sorting. */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arr = g_new(const NMSettInfoProperty *, property_infos_len);
|
|
|
|
|
for (i = 0; i < property_infos_len; i++)
|
|
|
|
|
arr[i] = &property_infos[i];
|
|
|
|
|
|
|
|
|
|
g_qsort_with_data(arr,
|
|
|
|
|
property_infos_len,
|
|
|
|
|
sizeof(const NMSettInfoProperty *),
|
|
|
|
|
_property_infos_sort_cmp_setting_connection,
|
|
|
|
|
NULL);
|
|
|
|
|
return arr;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 23:00:21 +02:00
|
|
|
static int
|
|
|
|
|
_property_lookup_by_param_spec_sort(gconstpointer p_a, gconstpointer p_b, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoPropertLookupByParamSpec *a = p_a;
|
|
|
|
|
const NMSettInfoPropertLookupByParamSpec *b = p_b;
|
|
|
|
|
|
|
|
|
|
NM_CMP_DIRECT(a->param_spec_as_uint, b->param_spec_as_uint);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
void
|
2021-06-28 14:53:16 +02:00
|
|
|
_nm_setting_class_commit(NMSettingClass * setting_class,
|
|
|
|
|
NMMetaSettingType meta_type,
|
|
|
|
|
const NMSettInfoSettDetail *detail,
|
|
|
|
|
GArray * properties_override,
|
|
|
|
|
gint16 private_offset)
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
{
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
NMSettInfoSetting *sett_info;
|
2021-06-28 23:00:21 +02:00
|
|
|
gs_free GParamSpec ** property_specs = NULL;
|
|
|
|
|
guint n_property_specs;
|
|
|
|
|
NMSettInfoPropertLookupByParamSpec *lookup_by_iter;
|
|
|
|
|
guint override_len;
|
|
|
|
|
guint i;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 j;
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
|
|
|
|
|
nm_assert(NM_IS_SETTING_CLASS(setting_class));
|
|
|
|
|
nm_assert(!setting_class->setting_info);
|
|
|
|
|
|
|
|
|
|
nm_assert(meta_type < G_N_ELEMENTS(_sett_info_settings));
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
sett_info = &_sett_info_settings[meta_type];
|
|
|
|
|
|
|
|
|
|
nm_assert(!sett_info->setting_class);
|
|
|
|
|
nm_assert(!sett_info->property_infos_len);
|
|
|
|
|
nm_assert(!sett_info->property_infos);
|
|
|
|
|
|
2021-06-21 14:52:47 +02:00
|
|
|
property_specs =
|
|
|
|
|
g_object_class_list_properties(G_OBJECT_CLASS(setting_class), &n_property_specs);
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
if (!properties_override) {
|
|
|
|
|
override_len = 0;
|
2021-06-21 14:52:47 +02:00
|
|
|
properties_override = _nm_sett_info_property_override_create_array_sized(n_property_specs);
|
|
|
|
|
} else {
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
override_len = properties_override->len;
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
|
2021-06-21 14:52:47 +02:00
|
|
|
for (i = 0; i < override_len; i++) {
|
|
|
|
|
NMSettInfoProperty *p = &g_array_index(properties_override, NMSettInfoProperty, i);
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
|
2021-06-21 14:52:47 +02:00
|
|
|
nm_assert((!!p->name) != (!!p->param_spec));
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
|
2021-06-21 14:52:47 +02:00
|
|
|
if (!p->name) {
|
|
|
|
|
nm_assert(p->param_spec);
|
|
|
|
|
p->name = p->param_spec->name;
|
|
|
|
|
} else
|
|
|
|
|
nm_assert(!p->param_spec);
|
|
|
|
|
}
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
}
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
#if NM_MORE_ASSERTS > 10
|
|
|
|
|
/* assert that properties_override is constructed consistently. */
|
|
|
|
|
for (i = 0; i < override_len; i++) {
|
|
|
|
|
const NMSettInfoProperty *p = &g_array_index(properties_override, NMSettInfoProperty, i);
|
2019-01-04 15:37:39 +01:00
|
|
|
gboolean found = FALSE;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint k;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
nm_assert(
|
|
|
|
|
!_nm_sett_info_property_find_in_array((NMSettInfoProperty *) properties_override->data,
|
|
|
|
|
i,
|
|
|
|
|
p->name));
|
2021-06-29 11:44:46 +02:00
|
|
|
for (k = 0; k < n_property_specs; k++) {
|
|
|
|
|
if (!nm_streq(property_specs[k]->name, p->name))
|
2019-01-04 15:37:39 +01:00
|
|
|
continue;
|
|
|
|
|
nm_assert(!found);
|
|
|
|
|
found = TRUE;
|
2021-06-29 11:44:46 +02:00
|
|
|
nm_assert(p->param_spec == property_specs[k]);
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
}
|
2019-01-04 15:37:39 +01:00
|
|
|
nm_assert(found == (p->param_spec != NULL));
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
}
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_property_specs; i++) {
|
|
|
|
|
const char * name = property_specs[i]->name;
|
|
|
|
|
NMSettInfoProperty *p;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
if (_nm_sett_info_property_find_in_array((NMSettInfoProperty *) properties_override->data,
|
|
|
|
|
override_len,
|
|
|
|
|
name))
|
|
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
g_array_set_size(properties_override, properties_override->len + 1);
|
|
|
|
|
p = &g_array_index(properties_override, NMSettInfoProperty, properties_override->len - 1);
|
|
|
|
|
memset(p, 0, sizeof(*p));
|
|
|
|
|
p->name = name;
|
|
|
|
|
p->param_spec = property_specs[i];
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 15:51:04 +02:00
|
|
|
for (i = 0; i < properties_override->len; i++) {
|
|
|
|
|
NMSettInfoProperty *p = &g_array_index(properties_override, NMSettInfoProperty, i);
|
|
|
|
|
GType vtype;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
if (p->property_type)
|
|
|
|
|
goto has_property_type;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 15:51:04 +02:00
|
|
|
nm_assert(p->param_spec);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 15:51:04 +02:00
|
|
|
vtype = p->param_spec->value_type;
|
2021-10-20 16:13:14 +02:00
|
|
|
if (vtype == G_TYPE_INT)
|
2019-09-22 10:57:57 +02:00
|
|
|
p->property_type = &nm_sett_info_propert_type_plain_i;
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_UINT)
|
2019-09-22 10:57:57 +02:00
|
|
|
p->property_type = &nm_sett_info_propert_type_plain_u;
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_INT64)
|
2021-06-29 14:23:16 +02:00
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE_GPROP(
|
|
|
|
|
G_VARIANT_TYPE_INT64,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
2021-06-29 18:06:46 +02:00
|
|
|
else if (vtype == G_TYPE_STRING) {
|
2021-06-29 22:28:07 +02:00
|
|
|
nm_assert(nm_streq(p->name, NM_SETTING_NAME)
|
|
|
|
|
== (!NM_FLAGS_HAS(p->param_spec->flags, G_PARAM_WRITABLE)));
|
|
|
|
|
if (!NM_FLAGS_HAS(p->param_spec->flags, G_PARAM_WRITABLE))
|
|
|
|
|
p->property_type = &nm_sett_info_propert_type_setting_name;
|
|
|
|
|
else {
|
2021-06-29 18:06:46 +02:00
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE_GPROP(
|
|
|
|
|
G_VARIANT_TYPE_STRING,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
2021-06-29 18:06:46 +02:00
|
|
|
}
|
|
|
|
|
} else if (vtype == G_TYPE_DOUBLE)
|
2021-06-29 14:23:16 +02:00
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE_GPROP(
|
|
|
|
|
G_VARIANT_TYPE_DOUBLE,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_STRV)
|
2021-06-29 14:23:16 +02:00
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE_GPROP(
|
|
|
|
|
G_VARIANT_TYPE_STRING_ARRAY,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
2021-10-20 16:13:14 +02:00
|
|
|
else if (g_type_is_a(vtype, G_TYPE_ENUM)) {
|
libnm: add type enum for handling gprop differences in to_dbus_fcn
For GBytes, GEnum, GFlags and others, we need special converters from the
default GObject properties to GVariant.
Previously, those were implemented by providing a special
gprop_to_dbus_fcn hook. But gprop_to_dbus_fcn should move
from NMSettInfoPropertType to NMSettInfoProperty, because it's
usually a per-property meta data, and not a per-property-type meta data.
The difference is whether the meta data can be shared between different
properties (of the same "type).
In these cases, this extra information is indeed part of the type.
We want to have a generic NM_SETT_INFO_PROPERT_TYPE_GPROP() property
(using _nm_setting_property_to_dbus_fcn_gprop()), but then we would like
to distinguish between special cases. So this was fine.
However, I find the approach of providing a gprop_to_dbus_fcn in this
case cumbersome. It makes it harder to understand what happens. Instead,
introduce a new "gprop_type" for the different types that
_nm_setting_property_to_dbus_fcn_gprop() can handle.
This new "gprop_type" is extra data of the property type, so
introduce a new field "typdata_to_dbus".
2021-06-18 09:43:20 +02:00
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE_GPROP(
|
|
|
|
|
G_VARIANT_TYPE_INT32,
|
2021-06-29 14:23:16 +02:00
|
|
|
.typdata_to_dbus.gprop_type = NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_ENUM,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
2019-04-24 15:51:04 +02:00
|
|
|
} else if (g_type_is_a(vtype, G_TYPE_FLAGS)) {
|
libnm: add type enum for handling gprop differences in to_dbus_fcn
For GBytes, GEnum, GFlags and others, we need special converters from the
default GObject properties to GVariant.
Previously, those were implemented by providing a special
gprop_to_dbus_fcn hook. But gprop_to_dbus_fcn should move
from NMSettInfoPropertType to NMSettInfoProperty, because it's
usually a per-property meta data, and not a per-property-type meta data.
The difference is whether the meta data can be shared between different
properties (of the same "type).
In these cases, this extra information is indeed part of the type.
We want to have a generic NM_SETT_INFO_PROPERT_TYPE_GPROP() property
(using _nm_setting_property_to_dbus_fcn_gprop()), but then we would like
to distinguish between special cases. So this was fine.
However, I find the approach of providing a gprop_to_dbus_fcn in this
case cumbersome. It makes it harder to understand what happens. Instead,
introduce a new "gprop_type" for the different types that
_nm_setting_property_to_dbus_fcn_gprop() can handle.
This new "gprop_type" is extra data of the property type, so
introduce a new field "typdata_to_dbus".
2021-06-18 09:43:20 +02:00
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE_GPROP(
|
|
|
|
|
G_VARIANT_TYPE_UINT32,
|
2021-06-29 14:23:16 +02:00
|
|
|
.typdata_to_dbus.gprop_type = NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_FLAGS,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
} else
|
|
|
|
|
nm_assert_not_reached();
|
2019-04-24 15:51:04 +02:00
|
|
|
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
has_property_type:
|
|
|
|
|
nm_assert(p->property_type);
|
|
|
|
|
nm_assert(p->property_type->dbus_type);
|
|
|
|
|
nm_assert(g_variant_type_string_is_valid((const char *) p->property_type->dbus_type));
|
2019-04-24 15:51:04 +02:00
|
|
|
}
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMSettInfoProperty, name) == 0);
|
|
|
|
|
g_array_sort(properties_override, nm_strcmp_p);
|
|
|
|
|
|
|
|
|
|
setting_class->setting_info = &nm_meta_setting_infos[meta_type];
|
|
|
|
|
sett_info->setting_class = setting_class;
|
2021-06-28 14:53:16 +02:00
|
|
|
|
|
|
|
|
if (private_offset == NM_SETT_INFO_PRIVATE_OFFSET_FROM_CLASS) {
|
|
|
|
|
int o;
|
|
|
|
|
|
|
|
|
|
o = g_type_class_get_instance_private_offset(setting_class);
|
|
|
|
|
nm_assert(o != NM_SETT_INFO_PRIVATE_OFFSET_FROM_CLASS);
|
|
|
|
|
nm_assert(o > G_MININT16);
|
|
|
|
|
nm_assert(o < 0);
|
|
|
|
|
private_offset = o;
|
|
|
|
|
}
|
|
|
|
|
sett_info->private_offset = private_offset;
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
if (detail)
|
|
|
|
|
sett_info->detail = *detail;
|
2019-09-22 16:21:00 +02:00
|
|
|
nm_assert(properties_override->len > 0);
|
2021-06-29 11:44:46 +02:00
|
|
|
nm_assert(properties_override->len < G_MAXUINT16);
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
sett_info->property_infos_len = properties_override->len;
|
2019-09-22 16:21:00 +02:00
|
|
|
sett_info->property_infos =
|
|
|
|
|
nm_memdup(properties_override->data, sizeof(NMSettInfoProperty) * properties_override->len);
|
2019-01-04 15:37:39 +01:00
|
|
|
|
|
|
|
|
sett_info->property_infos_sorted = _property_infos_sort(sett_info->property_infos,
|
|
|
|
|
sett_info->property_infos_len,
|
|
|
|
|
setting_class);
|
2019-09-22 16:21:00 +02:00
|
|
|
|
2021-06-28 23:00:21 +02:00
|
|
|
nm_assert(sett_info->property_infos_len < G_MAXUINT16);
|
|
|
|
|
sett_info->property_lookup_by_param_spec_len = 0;
|
2021-06-29 11:44:46 +02:00
|
|
|
for (j = 0; j < sett_info->property_infos_len; j++) {
|
|
|
|
|
if (sett_info->property_infos[j].param_spec) {
|
2021-06-28 23:00:21 +02:00
|
|
|
sett_info->property_lookup_by_param_spec_len++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sett_info->property_lookup_by_param_spec =
|
|
|
|
|
g_new(NMSettInfoPropertLookupByParamSpec, sett_info->property_lookup_by_param_spec_len);
|
|
|
|
|
lookup_by_iter =
|
|
|
|
|
(NMSettInfoPropertLookupByParamSpec *) sett_info->property_lookup_by_param_spec;
|
2021-06-29 11:44:46 +02:00
|
|
|
for (j = 0; j < sett_info->property_infos_len; j++) {
|
|
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[j];
|
2021-06-28 23:00:21 +02:00
|
|
|
|
|
|
|
|
if (property_info->param_spec) {
|
|
|
|
|
*(lookup_by_iter++) = (NMSettInfoPropertLookupByParamSpec){
|
|
|
|
|
.param_spec_as_uint = (uintptr_t) ((gpointer) property_info->param_spec),
|
|
|
|
|
.property_info = property_info,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_qsort_with_data(sett_info->property_lookup_by_param_spec,
|
|
|
|
|
sett_info->property_lookup_by_param_spec_len,
|
|
|
|
|
sizeof(NMSettInfoPropertLookupByParamSpec),
|
|
|
|
|
_property_lookup_by_param_spec_sort,
|
|
|
|
|
NULL);
|
|
|
|
|
|
2019-09-22 16:21:00 +02:00
|
|
|
g_array_free(properties_override, TRUE);
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
}
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
const NMSettInfoProperty *
|
2019-01-10 19:50:14 +01:00
|
|
|
_nm_sett_info_setting_get_property_info(const NMSettInfoSetting *sett_info,
|
|
|
|
|
const char * property_name)
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
{
|
2021-06-29 12:04:00 +02:00
|
|
|
const NMSettInfoProperty *property_info;
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
gssize idx;
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
|
2019-01-10 19:50:14 +01:00
|
|
|
nm_assert(property_name);
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
if (!sett_info)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMSettInfoProperty, name) == 0);
|
|
|
|
|
idx = nm_utils_array_find_binary_search(sett_info->property_infos,
|
|
|
|
|
sizeof(NMSettInfoProperty),
|
|
|
|
|
sett_info->property_infos_len,
|
|
|
|
|
&property_name,
|
|
|
|
|
nm_strcmp_p_with_data,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (idx < 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
property_info = &sett_info->property_infos[idx];
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(idx == 0 || strcmp(property_info[-1].name, property_info[0].name) < 0);
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
nm_assert(idx == sett_info->property_infos_len - 1
|
2021-06-29 12:04:00 +02:00
|
|
|
|| strcmp(property_info[0].name, property_info[1].name) < 0);
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
return property_info;
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
}
|
|
|
|
|
|
2019-01-10 19:50:14 +01:00
|
|
|
const NMSettInfoSetting *
|
|
|
|
|
_nm_setting_class_get_sett_info(NMSettingClass *setting_class)
|
|
|
|
|
{
|
2019-01-11 15:16:33 +01:00
|
|
|
const NMSettInfoSetting *sett_info;
|
|
|
|
|
|
|
|
|
|
if (!NM_IS_SETTING_CLASS(setting_class) || !setting_class->setting_info)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
nm_assert(setting_class->setting_info->meta_type < G_N_ELEMENTS(_sett_info_settings));
|
|
|
|
|
sett_info = &_sett_info_settings[setting_class->setting_info->meta_type];
|
|
|
|
|
nm_assert(sett_info->setting_class == setting_class);
|
|
|
|
|
return sett_info;
|
2019-01-10 19:50:14 +01:00
|
|
|
}
|
|
|
|
|
|
2021-06-28 23:00:21 +02:00
|
|
|
const NMSettInfoProperty *
|
|
|
|
|
_nm_sett_info_property_lookup_by_param_spec(const NMSettInfoSetting *sett_info,
|
|
|
|
|
const GParamSpec * param_spec)
|
|
|
|
|
{
|
|
|
|
|
NMSettInfoPropertLookupByParamSpec needle;
|
|
|
|
|
int imin;
|
|
|
|
|
int imax;
|
|
|
|
|
int imid;
|
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
|
|
nm_assert(sett_info);
|
|
|
|
|
nm_assert(param_spec);
|
|
|
|
|
|
|
|
|
|
/* ensure that "int" is large enough to contain the index variables. */
|
|
|
|
|
G_STATIC_ASSERT_EXPR(sizeof(int) > sizeof(sett_info->property_lookup_by_param_spec_len));
|
|
|
|
|
|
|
|
|
|
if (sett_info->property_lookup_by_param_spec_len == 0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
needle.param_spec_as_uint = (uintptr_t) ((gpointer) param_spec);
|
|
|
|
|
|
|
|
|
|
imin = 0;
|
|
|
|
|
imax = sett_info->property_lookup_by_param_spec_len - 1;
|
|
|
|
|
while (imin <= imax) {
|
|
|
|
|
imid = imin + (imax - imin) / 2;
|
|
|
|
|
|
|
|
|
|
cmp = _property_lookup_by_param_spec_sort(&sett_info->property_lookup_by_param_spec[imid],
|
|
|
|
|
&needle,
|
|
|
|
|
NULL);
|
|
|
|
|
if (cmp == 0)
|
|
|
|
|
return sett_info->property_lookup_by_param_spec[imid].property_info;
|
|
|
|
|
|
|
|
|
|
if (cmp < 0)
|
|
|
|
|
imin = imid + 1;
|
|
|
|
|
else
|
|
|
|
|
imax = imid - 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2019-01-20 13:49:08 +01:00
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_nm_setting_emit_property_changed(NMSetting *setting)
|
|
|
|
|
{
|
|
|
|
|
/* Some settings have "properties" that are not implemented as GObject properties.
|
|
|
|
|
*
|
|
|
|
|
* For example:
|
|
|
|
|
*
|
|
|
|
|
* - gendata-base settings like NMSettingEthtool. Here properties are just
|
|
|
|
|
* GVariant values in the gendata hash.
|
|
|
|
|
*
|
|
|
|
|
* - NMSettingWireGuard's peers are not backed by a GObject property. Instead
|
|
|
|
|
* there is C-API to access/modify peers.
|
|
|
|
|
*
|
|
|
|
|
* We still want to emit property-changed notifications for such properties,
|
|
|
|
|
* in particular because NMConnection registers to such signals to re-emit
|
|
|
|
|
* it as NM_CONNECTION_CHANGED signal. In fact, there are unlikely any other
|
|
|
|
|
* uses of such a property-changed signal, because generally it doesn't make
|
|
|
|
|
* too much sense.
|
|
|
|
|
*
|
|
|
|
|
* So, instead of adding yet another (artificial) signal "setting-changed",
|
|
|
|
|
* hijack the "notify" signal and just notify about changes of the "name".
|
|
|
|
|
* Of course, the "name" doesn't really ever change, because it's tied to
|
|
|
|
|
* the GObject's type.
|
|
|
|
|
*/
|
|
|
|
|
_notify(setting, PROP_NAME);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
|
2018-07-29 13:25:49 +02:00
|
|
|
gboolean
|
|
|
|
|
_nm_setting_use_legacy_property(NMSetting * setting,
|
|
|
|
|
GVariant * connection_dict,
|
|
|
|
|
const char *legacy_property,
|
|
|
|
|
const char *new_property)
|
|
|
|
|
{
|
2021-07-27 13:27:53 +02:00
|
|
|
gs_unref_variant GVariant *setting_dict = NULL;
|
|
|
|
|
gs_unref_variant GVariant *value = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: use from_dbus_fcn() property callback from update_one_secret()
Our handling of properties is relatively complicated. We should have
clear code paths and responsibilities who calls who.
There is from_dbus_fcn() callback to implement parsing a GVariant and
set the property in NMSetting. This is called via:
- _nm_setting_new_from_dbus()
- init_from_dbus()
- _property_set_from_dbus()
Then, one of the from_dbus_fcn() implementations is
_nm_setting_property_from_dbus_fcn_gprop(), which calls
set_property_from_dbus(). That one sets the property using GObject
setter. That's good and a clear code path.
However, set_property_from_dbus() was also called via
- _nm_setting_update_secrets()
- klass->update_one_secret()
- nm-setting.c:update_one_secret()
- set_property_from_dbus()
Meaning, there is a different code path to set_property_from_dbus(),
which bypasses from_dbus_fcn(). That is highly undesirable, because
it should be clear how a property setter gets implemented, and this
way, potentially two different implementations were used.
Refactor nm-setting.c:update_one_secret() to use
_property_set_from_dbus() instead. This behaves potentially differently
for properties like NM_SETTING_ADSL_PASSWORD, which is implemented as
a "direct" property, where from_dbus_fcn() setter no longer uses g_object_set().
This should not make a difference in practice, and in any case, now the
code paths are unified.
2021-07-26 22:42:25 +02:00
|
|
|
if (!connection_dict) {
|
|
|
|
|
/* we also allow the caller to provide no connection_dict.
|
|
|
|
|
*
|
|
|
|
|
* We hit this code bug when being called by update_one_secret().
|
|
|
|
|
* In this case, we use the legacy property, because we are not
|
|
|
|
|
* sophisticated enough to mediate between deprecated and legacy
|
|
|
|
|
* properties...
|
|
|
|
|
*
|
|
|
|
|
* However, in practice this code is unreachable, because update_one_secret()
|
|
|
|
|
* only ends up calling from_dbus_fcn() for certain properties, and none
|
|
|
|
|
* of those are actually deprecated (for now). So this cannot really happen. */
|
|
|
|
|
return nm_assert_unreachable_val(FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-29 13:25:49 +02:00
|
|
|
setting_dict = g_variant_lookup_value(connection_dict,
|
|
|
|
|
nm_setting_get_name(NM_SETTING(setting)),
|
|
|
|
|
NM_VARIANT_TYPE_SETTING);
|
2021-07-27 13:27:53 +02:00
|
|
|
|
2018-07-29 13:25:49 +02:00
|
|
|
g_return_val_if_fail(setting_dict != NULL, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-07-29 13:25:49 +02:00
|
|
|
/* If the new property isn't set, we have to use the legacy property. */
|
|
|
|
|
value = g_variant_lookup_value(setting_dict, new_property, NULL);
|
2021-07-27 13:27:53 +02:00
|
|
|
if (!value)
|
2018-07-29 13:25:49 +02:00
|
|
|
return TRUE;
|
2021-07-27 13:27:53 +02:00
|
|
|
nm_clear_pointer(&value, g_variant_unref);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-07-29 13:25:49 +02:00
|
|
|
/* Otherwise, clients always prefer new properties sent from the daemon. */
|
2021-07-27 13:27:53 +02:00
|
|
|
if (!_nm_utils_is_manager_process)
|
2018-07-29 13:25:49 +02:00
|
|
|
return FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2018-07-29 13:25:49 +02:00
|
|
|
/* The daemon prefers the legacy property if it exists. */
|
|
|
|
|
value = g_variant_lookup_value(setting_dict, legacy_property, NULL);
|
2021-07-27 13:27:53 +02:00
|
|
|
return !!value;
|
2018-07-29 13:25:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-07-14 07:40:35 +02:00
|
|
|
static gboolean
|
|
|
|
|
_property_direct_set_string(const NMSettInfoProperty *property_info, char **dst, const char *src)
|
|
|
|
|
{
|
|
|
|
|
if (property_info->direct_set_string_ascii_strdown)
|
2021-07-30 09:04:53 +02:00
|
|
|
return nm_strdup_reset_take(dst, src ? g_ascii_strdown(src, -1) : NULL);
|
2021-07-14 07:40:35 +02:00
|
|
|
if (property_info->direct_set_string_mac_address_len > 0) {
|
2021-07-30 09:04:53 +02:00
|
|
|
return nm_strdup_reset_take(dst,
|
|
|
|
|
_nm_utils_hwaddr_canonical_or_invalid(
|
|
|
|
|
src,
|
|
|
|
|
property_info->direct_set_string_mac_address_len));
|
2021-07-14 07:40:35 +02:00
|
|
|
}
|
2021-07-14 07:40:35 +02:00
|
|
|
if (property_info->direct_set_string_ip_address_addr_family != 0) {
|
2021-07-30 09:04:53 +02:00
|
|
|
return nm_strdup_reset_take(dst,
|
|
|
|
|
_nm_utils_ipaddr_canonical_or_invalid(
|
|
|
|
|
property_info->direct_set_string_ip_address_addr_family,
|
|
|
|
|
src));
|
2021-07-14 07:40:35 +02:00
|
|
|
}
|
2021-07-30 09:04:53 +02:00
|
|
|
return nm_strdup_reset(dst, src);
|
2021-07-14 07:40:35 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-28 20:48:40 +02:00
|
|
|
void
|
|
|
|
|
_nm_setting_property_get_property_direct(GObject * object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
GValue * value,
|
|
|
|
|
GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
NMSetting * setting = NM_SETTING(object);
|
|
|
|
|
const NMSettInfoSetting * sett_info;
|
|
|
|
|
const NMSettInfoProperty *property_info;
|
|
|
|
|
|
|
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
|
|
|
|
nm_assert(sett_info);
|
|
|
|
|
|
|
|
|
|
property_info = _nm_sett_info_property_lookup_by_param_spec(sett_info, pspec);
|
|
|
|
|
if (!property_info)
|
|
|
|
|
goto out_fail;
|
|
|
|
|
|
|
|
|
|
nm_assert(property_info->param_spec == pspec);
|
|
|
|
|
|
|
|
|
|
switch (property_info->property_type->direct_type) {
|
|
|
|
|
case NM_VALUE_TYPE_BOOL:
|
|
|
|
|
{
|
|
|
|
|
const bool *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
g_value_set_boolean(value, *p_val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-07-13 22:56:05 +02:00
|
|
|
case NM_VALUE_TYPE_INT32:
|
|
|
|
|
{
|
|
|
|
|
const gint32 *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
g_value_set_int(value, *p_val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-06-29 07:57:41 +02:00
|
|
|
case NM_VALUE_TYPE_UINT32:
|
|
|
|
|
{
|
|
|
|
|
const guint32 *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
g_value_set_uint(value, *p_val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_UINT64:
|
|
|
|
|
{
|
|
|
|
|
const guint64 *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
g_value_set_uint64(value, *p_val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_ENUM:
|
|
|
|
|
{
|
|
|
|
|
const int *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
g_value_set_enum(value, *p_val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_FLAGS:
|
|
|
|
|
{
|
|
|
|
|
const guint *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
g_value_set_flags(value, *p_val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-06-28 20:48:40 +02:00
|
|
|
case NM_VALUE_TYPE_STRING:
|
|
|
|
|
{
|
|
|
|
|
const char *const *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
g_value_set_string(value, *p_val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-10-27 20:24:17 +02:00
|
|
|
case NM_VALUE_TYPE_BYTES:
|
|
|
|
|
{
|
|
|
|
|
const GBytes *const *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
g_value_set_boxed(value, *p_val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-06-28 20:48:40 +02:00
|
|
|
default:
|
|
|
|
|
goto out_fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
out_fail:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_nm_setting_property_set_property_direct(GObject * object,
|
|
|
|
|
guint prop_id,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamSpec * pspec)
|
|
|
|
|
{
|
|
|
|
|
NMSetting * setting = NM_SETTING(object);
|
|
|
|
|
const NMSettInfoSetting * sett_info;
|
|
|
|
|
const NMSettInfoProperty *property_info;
|
|
|
|
|
|
|
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
|
|
|
|
nm_assert(sett_info);
|
|
|
|
|
|
|
|
|
|
property_info = _nm_sett_info_property_lookup_by_param_spec(sett_info, pspec);
|
|
|
|
|
if (!property_info)
|
|
|
|
|
goto out_fail;
|
|
|
|
|
|
|
|
|
|
nm_assert(property_info->param_spec == pspec);
|
|
|
|
|
|
|
|
|
|
switch (property_info->property_type->direct_type) {
|
|
|
|
|
case NM_VALUE_TYPE_BOOL:
|
|
|
|
|
{
|
|
|
|
|
bool * p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
gboolean v;
|
|
|
|
|
|
|
|
|
|
v = g_value_get_boolean(value);
|
|
|
|
|
if (*p_val == v)
|
|
|
|
|
return;
|
|
|
|
|
*p_val = v;
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-07-13 22:56:05 +02:00
|
|
|
case NM_VALUE_TYPE_INT32:
|
|
|
|
|
{
|
|
|
|
|
gint32 *p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
int v;
|
|
|
|
|
|
|
|
|
|
v = g_value_get_int(value);
|
|
|
|
|
if (*p_val == v)
|
|
|
|
|
return;
|
|
|
|
|
*p_val = v;
|
|
|
|
|
|
|
|
|
|
/* truncation cannot happen, because the param_spec is supposed to have suitable
|
|
|
|
|
* minimum/maximum values so that we are in range for int32. */
|
|
|
|
|
nm_assert(*p_val == v);
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-06-29 07:57:41 +02:00
|
|
|
case NM_VALUE_TYPE_UINT32:
|
|
|
|
|
{
|
|
|
|
|
guint32 *p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
guint v;
|
|
|
|
|
|
|
|
|
|
v = g_value_get_uint(value);
|
|
|
|
|
if (*p_val == v)
|
|
|
|
|
return;
|
|
|
|
|
*p_val = v;
|
|
|
|
|
|
|
|
|
|
/* truncation cannot happen, because the param_spec is supposed to have suitable
|
|
|
|
|
* minimum/maximum values so that we are in range for uint32. */
|
|
|
|
|
nm_assert(*p_val == v);
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_UINT64:
|
|
|
|
|
{
|
|
|
|
|
guint64 *p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
guint64 v;
|
|
|
|
|
|
|
|
|
|
v = g_value_get_uint64(value);
|
|
|
|
|
if (*p_val == v)
|
|
|
|
|
return;
|
|
|
|
|
*p_val = v;
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_ENUM:
|
|
|
|
|
{
|
|
|
|
|
int *p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
int v;
|
|
|
|
|
|
|
|
|
|
v = g_value_get_enum(value);
|
|
|
|
|
if (*p_val == v)
|
|
|
|
|
return;
|
|
|
|
|
*p_val = v;
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_FLAGS:
|
|
|
|
|
{
|
|
|
|
|
guint *p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
guint v;
|
|
|
|
|
|
|
|
|
|
v = g_value_get_flags(value);
|
|
|
|
|
if (*p_val == v)
|
|
|
|
|
return;
|
|
|
|
|
*p_val = v;
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-06-28 20:48:40 +02:00
|
|
|
case NM_VALUE_TYPE_STRING:
|
2021-07-14 07:40:35 +02:00
|
|
|
if (!_property_direct_set_string(
|
|
|
|
|
property_info,
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset),
|
|
|
|
|
g_value_get_string(value)))
|
2021-06-28 20:48:40 +02:00
|
|
|
return;
|
|
|
|
|
goto out_notify;
|
2021-10-27 20:24:17 +02:00
|
|
|
case NM_VALUE_TYPE_BYTES:
|
|
|
|
|
{
|
|
|
|
|
GBytes **p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
GBytes * v;
|
|
|
|
|
_nm_unused gs_unref_bytes GBytes *old = NULL;
|
|
|
|
|
|
|
|
|
|
v = g_value_get_boxed(value);
|
|
|
|
|
if (nm_g_bytes_equal0(*p_val, v))
|
|
|
|
|
return;
|
|
|
|
|
old = *p_val;
|
|
|
|
|
*p_val = v ? g_bytes_ref(v) : NULL;
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-06-28 20:48:40 +02:00
|
|
|
default:
|
|
|
|
|
goto out_fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
out_notify:
|
|
|
|
|
/* If explicit-notify would be set, we would need to emit g_object_notify_by_pspec().
|
|
|
|
|
*
|
|
|
|
|
* Currently we never set that, also because we still support glib 2.40. */
|
|
|
|
|
nm_assert(!NM_FLAGS_HAS(pspec->flags, 1 << 30 /* G_PARAM_EXPLICIT_NOTIFY */));
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
out_fail:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-06-29 08:52:02 +02:00
|
|
|
static void
|
|
|
|
|
_init_direct(NMSetting *setting)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoSetting *sett_info;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 i;
|
2021-06-29 08:52:02 +02:00
|
|
|
|
|
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
|
|
|
|
nm_assert(sett_info);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
|
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
|
|
|
|
|
|
|
|
|
|
/* We don't emit any g_object_notify_by_pspec(), because this is
|
|
|
|
|
* only supposed to be called during initialization of the GObject
|
|
|
|
|
* instance. */
|
|
|
|
|
|
|
|
|
|
switch (property_info->property_type->direct_type) {
|
|
|
|
|
case NM_VALUE_TYPE_NONE:
|
|
|
|
|
break;
|
|
|
|
|
case NM_VALUE_TYPE_BOOL:
|
|
|
|
|
{
|
|
|
|
|
bool *p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
gboolean def_val;
|
|
|
|
|
|
|
|
|
|
def_val = NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN(property_info->param_spec);
|
|
|
|
|
nm_assert(*p_val == FALSE);
|
|
|
|
|
*p_val = def_val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-07-13 22:56:05 +02:00
|
|
|
case NM_VALUE_TYPE_INT32:
|
|
|
|
|
{
|
|
|
|
|
gint32 *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
int def_val;
|
|
|
|
|
|
|
|
|
|
def_val = NM_G_PARAM_SPEC_GET_DEFAULT_INT(property_info->param_spec);
|
|
|
|
|
nm_assert(*p_val == 0);
|
|
|
|
|
*p_val = def_val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-06-29 08:52:02 +02:00
|
|
|
case NM_VALUE_TYPE_UINT32:
|
|
|
|
|
{
|
|
|
|
|
guint32 *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
guint def_val;
|
|
|
|
|
|
|
|
|
|
def_val = NM_G_PARAM_SPEC_GET_DEFAULT_UINT(property_info->param_spec);
|
|
|
|
|
nm_assert(*p_val == 0);
|
|
|
|
|
*p_val = def_val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_UINT64:
|
|
|
|
|
{
|
|
|
|
|
guint64 *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
guint64 def_val;
|
|
|
|
|
|
|
|
|
|
def_val = NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(property_info->param_spec);
|
|
|
|
|
nm_assert(*p_val == 0);
|
|
|
|
|
*p_val = def_val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_ENUM:
|
|
|
|
|
{
|
|
|
|
|
int *p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
int def_val;
|
|
|
|
|
|
|
|
|
|
def_val = NM_G_PARAM_SPEC_GET_DEFAULT_ENUM(property_info->param_spec);
|
|
|
|
|
nm_assert(*p_val == 0);
|
|
|
|
|
*p_val = def_val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_FLAGS:
|
|
|
|
|
{
|
|
|
|
|
guint *p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
guint def_val;
|
|
|
|
|
|
|
|
|
|
def_val = NM_G_PARAM_SPEC_GET_DEFAULT_FLAGS(property_info->param_spec);
|
|
|
|
|
nm_assert(*p_val == 0);
|
|
|
|
|
*p_val = def_val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-06-29 08:52:02 +02:00
|
|
|
case NM_VALUE_TYPE_STRING:
|
|
|
|
|
nm_assert(!NM_G_PARAM_SPEC_GET_DEFAULT_STRING(property_info->param_spec));
|
|
|
|
|
nm_assert(!(
|
|
|
|
|
*((const char *const *)
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset))));
|
|
|
|
|
break;
|
2021-10-27 20:24:17 +02:00
|
|
|
case NM_VALUE_TYPE_BYTES:
|
|
|
|
|
nm_assert(!(
|
|
|
|
|
*((const GBytes *const *)
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset))));
|
|
|
|
|
break;
|
2021-06-29 08:52:02 +02:00
|
|
|
default:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-28 23:51:42 +02:00
|
|
|
static void
|
|
|
|
|
_finalize_direct(NMSetting *setting)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoSetting *sett_info;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 i;
|
2021-06-28 23:51:42 +02:00
|
|
|
|
|
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
|
|
|
|
nm_assert(sett_info);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
|
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
|
|
|
|
|
|
|
|
|
|
/* We only:
|
|
|
|
|
*
|
|
|
|
|
* - reset fields where there is something to free. E.g. boolean
|
|
|
|
|
* properties are not reset to their default.
|
|
|
|
|
* - clear/free properties, without emitting g_object_notify_by_pspec(),
|
|
|
|
|
* because this is called only during finalization. */
|
|
|
|
|
|
|
|
|
|
switch (property_info->property_type->direct_type) {
|
|
|
|
|
case NM_VALUE_TYPE_NONE:
|
|
|
|
|
case NM_VALUE_TYPE_BOOL:
|
2021-07-13 22:56:05 +02:00
|
|
|
case NM_VALUE_TYPE_INT32:
|
2021-06-29 07:57:41 +02:00
|
|
|
case NM_VALUE_TYPE_UINT32:
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_UINT64:
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_ENUM:
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_FLAGS:
|
2021-06-28 23:51:42 +02:00
|
|
|
break;
|
|
|
|
|
case NM_VALUE_TYPE_STRING:
|
|
|
|
|
{
|
|
|
|
|
char **p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
nm_clear_g_free(p_val);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-10-27 20:24:17 +02:00
|
|
|
case NM_VALUE_TYPE_BYTES:
|
|
|
|
|
{
|
|
|
|
|
GBytes **p_val =
|
|
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
nm_clear_pointer(p_val, g_bytes_unref);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-06-28 23:51:42 +02:00
|
|
|
default:
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-06-28 17:04:37 +02:00
|
|
|
GVariant *
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_to_dbus_fcn_direct(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
2021-06-28 17:04:37 +02:00
|
|
|
{
|
|
|
|
|
switch (property_info->property_type->direct_type) {
|
|
|
|
|
case NM_VALUE_TYPE_BOOL:
|
|
|
|
|
{
|
|
|
|
|
gboolean val;
|
|
|
|
|
|
|
|
|
|
val = *((bool *) _nm_setting_get_private(setting, sett_info, property_info->direct_offset));
|
2021-06-29 22:11:08 +02:00
|
|
|
if (!property_info->to_dbus_including_default
|
2021-06-28 17:04:37 +02:00
|
|
|
&& val == NM_G_PARAM_SPEC_GET_DEFAULT_BOOLEAN(property_info->param_spec))
|
|
|
|
|
return NULL;
|
|
|
|
|
return g_variant_ref(nm_g_variant_singleton_b(val));
|
|
|
|
|
}
|
2021-07-13 22:56:05 +02:00
|
|
|
case NM_VALUE_TYPE_INT32:
|
|
|
|
|
{
|
|
|
|
|
gint32 val;
|
|
|
|
|
|
|
|
|
|
val =
|
|
|
|
|
*((gint32 *) _nm_setting_get_private(setting, sett_info, property_info->direct_offset));
|
|
|
|
|
if (!property_info->to_dbus_including_default
|
|
|
|
|
&& val == NM_G_PARAM_SPEC_GET_DEFAULT_INT(property_info->param_spec))
|
|
|
|
|
return NULL;
|
2021-10-20 10:53:39 +02:00
|
|
|
return nm_g_variant_maybe_singleton_i(val);
|
2021-07-13 22:56:05 +02:00
|
|
|
}
|
2021-06-29 07:57:41 +02:00
|
|
|
case NM_VALUE_TYPE_UINT32:
|
|
|
|
|
{
|
|
|
|
|
guint32 val;
|
|
|
|
|
|
|
|
|
|
val = *(
|
|
|
|
|
(guint32 *) _nm_setting_get_private(setting, sett_info, property_info->direct_offset));
|
2021-06-29 22:11:08 +02:00
|
|
|
if (!property_info->to_dbus_including_default
|
2021-06-29 07:57:41 +02:00
|
|
|
&& val == NM_G_PARAM_SPEC_GET_DEFAULT_UINT(property_info->param_spec))
|
|
|
|
|
return NULL;
|
|
|
|
|
return g_variant_new_uint32(val);
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_UINT64:
|
|
|
|
|
{
|
|
|
|
|
guint64 val;
|
|
|
|
|
|
|
|
|
|
val = *(
|
|
|
|
|
(guint64 *) _nm_setting_get_private(setting, sett_info, property_info->direct_offset));
|
|
|
|
|
if (!property_info->to_dbus_including_default
|
|
|
|
|
&& val == NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(property_info->param_spec))
|
|
|
|
|
return NULL;
|
|
|
|
|
return g_variant_new_uint64(val);
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_ENUM:
|
|
|
|
|
{
|
|
|
|
|
int val;
|
|
|
|
|
|
|
|
|
|
val = *((int *) _nm_setting_get_private(setting, sett_info, property_info->direct_offset));
|
|
|
|
|
if (!property_info->to_dbus_including_default
|
|
|
|
|
&& val == NM_G_PARAM_SPEC_GET_DEFAULT_ENUM(property_info->param_spec))
|
|
|
|
|
return NULL;
|
|
|
|
|
return nm_g_variant_maybe_singleton_i(val);
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_FLAGS:
|
|
|
|
|
{
|
|
|
|
|
guint val;
|
|
|
|
|
|
|
|
|
|
val =
|
|
|
|
|
*((guint *) _nm_setting_get_private(setting, sett_info, property_info->direct_offset));
|
|
|
|
|
if (!property_info->to_dbus_including_default
|
|
|
|
|
&& val == NM_G_PARAM_SPEC_GET_DEFAULT_FLAGS(property_info->param_spec))
|
|
|
|
|
return NULL;
|
|
|
|
|
return g_variant_new_uint32(val);
|
|
|
|
|
}
|
2021-06-28 19:17:19 +02:00
|
|
|
case NM_VALUE_TYPE_STRING:
|
|
|
|
|
{
|
|
|
|
|
const char *val;
|
|
|
|
|
|
|
|
|
|
/* For string properties that are implemented via this function, the default is always NULL.
|
|
|
|
|
* In general, having strings default to NULL is most advisable.
|
|
|
|
|
*
|
|
|
|
|
* Setting "including_default" for a string makes no sense because a
|
|
|
|
|
* GVariant of type "s" cannot express NULL. */
|
|
|
|
|
nm_assert(!NM_G_PARAM_SPEC_GET_DEFAULT_STRING(property_info->param_spec));
|
2021-06-29 22:11:08 +02:00
|
|
|
nm_assert(!property_info->to_dbus_including_default);
|
2021-06-28 19:17:19 +02:00
|
|
|
|
|
|
|
|
val = *((const char *const *) _nm_setting_get_private(setting,
|
|
|
|
|
sett_info,
|
|
|
|
|
property_info->direct_offset));
|
|
|
|
|
if (!val)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (!val[0])
|
|
|
|
|
return g_variant_ref(nm_g_variant_singleton_s_empty());
|
|
|
|
|
return g_variant_new_string(val);
|
|
|
|
|
}
|
2021-10-27 20:24:17 +02:00
|
|
|
case NM_VALUE_TYPE_BYTES:
|
|
|
|
|
{
|
|
|
|
|
const GBytes *val;
|
|
|
|
|
|
|
|
|
|
/* Bytes have always NULL as default. Setting "including_default" has no defined meaning
|
|
|
|
|
* (but it could have). */
|
|
|
|
|
nm_assert(!property_info->to_dbus_including_default);
|
|
|
|
|
|
|
|
|
|
val = *((const GBytes *const *) _nm_setting_get_private(setting,
|
|
|
|
|
sett_info,
|
|
|
|
|
property_info->direct_offset));
|
|
|
|
|
if (!val)
|
|
|
|
|
return NULL;
|
|
|
|
|
return nm_g_bytes_to_variant_ay(val);
|
|
|
|
|
}
|
2021-06-28 17:04:37 +02:00
|
|
|
default:
|
|
|
|
|
return nm_assert_unreachable_val(NULL);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-13 18:09:13 +02:00
|
|
|
GVariant *
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_to_dbus_fcn_direct_mac_address(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
2021-07-13 18:09:13 +02:00
|
|
|
{
|
|
|
|
|
const char *val;
|
|
|
|
|
|
|
|
|
|
nm_assert(property_info->property_type == &nm_sett_info_propert_type_direct_mac_address);
|
|
|
|
|
nm_assert(property_info->property_type->direct_type == NM_VALUE_TYPE_STRING);
|
|
|
|
|
nm_assert(!NM_G_PARAM_SPEC_GET_DEFAULT_STRING(property_info->param_spec));
|
|
|
|
|
nm_assert(!property_info->to_dbus_including_default);
|
|
|
|
|
|
|
|
|
|
val = *((const char *const *) _nm_setting_get_private(setting,
|
|
|
|
|
sett_info,
|
|
|
|
|
property_info->direct_offset));
|
|
|
|
|
return nm_utils_hwaddr_to_dbus(val);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 22:28:07 +02:00
|
|
|
GVariant *
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_to_dbus_fcn_ignore(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
2021-06-29 22:28:07 +02:00
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-18 08:59:12 +02:00
|
|
|
GVariant *
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_to_dbus_fcn_gprop(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
2021-06-18 08:59:12 +02:00
|
|
|
{
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_auto_unset_gvalue GValue prop_value = {
|
2021-06-18 08:59:12 +02:00
|
|
|
0,
|
|
|
|
|
};
|
2021-06-18 11:04:03 +02:00
|
|
|
GArray *tmp_array;
|
2021-06-18 08:59:12 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(property_info->param_spec);
|
|
|
|
|
nm_assert(property_info->property_type->to_dbus_fcn == _nm_setting_property_to_dbus_fcn_gprop);
|
2021-06-18 08:59:12 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
g_value_init(&prop_value, property_info->param_spec->value_type);
|
2021-06-18 08:59:12 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
g_object_get_property(G_OBJECT(setting), property_info->param_spec->name, &prop_value);
|
2021-06-18 08:59:12 +02:00
|
|
|
|
2021-06-29 22:11:08 +02:00
|
|
|
if (!property_info->to_dbus_including_default
|
2021-06-29 12:04:00 +02:00
|
|
|
&& g_param_value_defaults(property_info->param_spec, &prop_value))
|
2021-06-18 08:59:12 +02:00
|
|
|
return NULL;
|
|
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
switch (property_info->property_type->typdata_to_dbus.gprop_type) {
|
libnm: add type enum for handling gprop differences in to_dbus_fcn
For GBytes, GEnum, GFlags and others, we need special converters from the
default GObject properties to GVariant.
Previously, those were implemented by providing a special
gprop_to_dbus_fcn hook. But gprop_to_dbus_fcn should move
from NMSettInfoPropertType to NMSettInfoProperty, because it's
usually a per-property meta data, and not a per-property-type meta data.
The difference is whether the meta data can be shared between different
properties (of the same "type).
In these cases, this extra information is indeed part of the type.
We want to have a generic NM_SETT_INFO_PROPERT_TYPE_GPROP() property
(using _nm_setting_property_to_dbus_fcn_gprop()), but then we would like
to distinguish between special cases. So this was fine.
However, I find the approach of providing a gprop_to_dbus_fcn in this
case cumbersome. It makes it harder to understand what happens. Instead,
introduce a new "gprop_type" for the different types that
_nm_setting_property_to_dbus_fcn_gprop() can handle.
This new "gprop_type" is extra data of the property type, so
introduce a new field "typdata_to_dbus".
2021-06-18 09:43:20 +02:00
|
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_DEFAULT:
|
2021-06-29 12:04:00 +02:00
|
|
|
return g_dbus_gvalue_to_gvariant(&prop_value, property_info->property_type->dbus_type);
|
libnm: add type enum for handling gprop differences in to_dbus_fcn
For GBytes, GEnum, GFlags and others, we need special converters from the
default GObject properties to GVariant.
Previously, those were implemented by providing a special
gprop_to_dbus_fcn hook. But gprop_to_dbus_fcn should move
from NMSettInfoPropertType to NMSettInfoProperty, because it's
usually a per-property meta data, and not a per-property-type meta data.
The difference is whether the meta data can be shared between different
properties (of the same "type).
In these cases, this extra information is indeed part of the type.
We want to have a generic NM_SETT_INFO_PROPERT_TYPE_GPROP() property
(using _nm_setting_property_to_dbus_fcn_gprop()), but then we would like
to distinguish between special cases. So this was fine.
However, I find the approach of providing a gprop_to_dbus_fcn in this
case cumbersome. It makes it harder to understand what happens. Instead,
introduce a new "gprop_type" for the different types that
_nm_setting_property_to_dbus_fcn_gprop() can handle.
This new "gprop_type" is extra data of the property type, so
introduce a new field "typdata_to_dbus".
2021-06-18 09:43:20 +02:00
|
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_ENUM:
|
2021-10-20 10:53:39 +02:00
|
|
|
return nm_g_variant_maybe_singleton_i(g_value_get_enum(&prop_value));
|
libnm: add type enum for handling gprop differences in to_dbus_fcn
For GBytes, GEnum, GFlags and others, we need special converters from the
default GObject properties to GVariant.
Previously, those were implemented by providing a special
gprop_to_dbus_fcn hook. But gprop_to_dbus_fcn should move
from NMSettInfoPropertType to NMSettInfoProperty, because it's
usually a per-property meta data, and not a per-property-type meta data.
The difference is whether the meta data can be shared between different
properties (of the same "type).
In these cases, this extra information is indeed part of the type.
We want to have a generic NM_SETT_INFO_PROPERT_TYPE_GPROP() property
(using _nm_setting_property_to_dbus_fcn_gprop()), but then we would like
to distinguish between special cases. So this was fine.
However, I find the approach of providing a gprop_to_dbus_fcn in this
case cumbersome. It makes it harder to understand what happens. Instead,
introduce a new "gprop_type" for the different types that
_nm_setting_property_to_dbus_fcn_gprop() can handle.
This new "gprop_type" is extra data of the property type, so
introduce a new field "typdata_to_dbus".
2021-06-18 09:43:20 +02:00
|
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_FLAGS:
|
|
|
|
|
return g_variant_new_uint32(g_value_get_flags(&prop_value));
|
2021-06-18 11:04:03 +02:00
|
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_GARRAY_UINT:
|
|
|
|
|
G_STATIC_ASSERT_EXPR(sizeof(guint) == sizeof(guint32));
|
|
|
|
|
nm_assert(G_VALUE_HOLDS(&prop_value, G_TYPE_ARRAY));
|
|
|
|
|
tmp_array = g_value_get_boxed(&prop_value);
|
|
|
|
|
nm_assert(tmp_array);
|
|
|
|
|
return nm_g_variant_new_au((const guint32 *) tmp_array->data, tmp_array->len);
|
2021-06-18 12:27:12 +02:00
|
|
|
case NM_SETTING_PROPERTY_TO_DBUS_FCN_GPROP_TYPE_STRDICT:
|
|
|
|
|
nm_assert(G_VALUE_HOLDS(&prop_value, G_TYPE_HASH_TABLE));
|
2021-07-30 09:15:38 +02:00
|
|
|
return nm_strdict_to_variant_ass(g_value_get_boxed(&prop_value));
|
libnm: add type enum for handling gprop differences in to_dbus_fcn
For GBytes, GEnum, GFlags and others, we need special converters from the
default GObject properties to GVariant.
Previously, those were implemented by providing a special
gprop_to_dbus_fcn hook. But gprop_to_dbus_fcn should move
from NMSettInfoPropertType to NMSettInfoProperty, because it's
usually a per-property meta data, and not a per-property-type meta data.
The difference is whether the meta data can be shared between different
properties (of the same "type).
In these cases, this extra information is indeed part of the type.
We want to have a generic NM_SETT_INFO_PROPERT_TYPE_GPROP() property
(using _nm_setting_property_to_dbus_fcn_gprop()), but then we would like
to distinguish between special cases. So this was fine.
However, I find the approach of providing a gprop_to_dbus_fcn in this
case cumbersome. It makes it harder to understand what happens. Instead,
introduce a new "gprop_type" for the different types that
_nm_setting_property_to_dbus_fcn_gprop() can handle.
This new "gprop_type" is extra data of the property type, so
introduce a new field "typdata_to_dbus".
2021-06-18 09:43:20 +02:00
|
|
|
}
|
2021-06-18 08:59:12 +02:00
|
|
|
|
libnm: add type enum for handling gprop differences in to_dbus_fcn
For GBytes, GEnum, GFlags and others, we need special converters from the
default GObject properties to GVariant.
Previously, those were implemented by providing a special
gprop_to_dbus_fcn hook. But gprop_to_dbus_fcn should move
from NMSettInfoPropertType to NMSettInfoProperty, because it's
usually a per-property meta data, and not a per-property-type meta data.
The difference is whether the meta data can be shared between different
properties (of the same "type).
In these cases, this extra information is indeed part of the type.
We want to have a generic NM_SETT_INFO_PROPERT_TYPE_GPROP() property
(using _nm_setting_property_to_dbus_fcn_gprop()), but then we would like
to distinguish between special cases. So this was fine.
However, I find the approach of providing a gprop_to_dbus_fcn in this
case cumbersome. It makes it harder to understand what happens. Instead,
introduce a new "gprop_type" for the different types that
_nm_setting_property_to_dbus_fcn_gprop() can handle.
This new "gprop_type" is extra data of the property type, so
introduce a new field "typdata_to_dbus".
2021-06-18 09:43:20 +02:00
|
|
|
return nm_assert_unreachable_val(NULL);
|
2021-06-18 08:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
2021-06-30 00:05:49 +02:00
|
|
|
gboolean
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_from_dbus_fcn_ignore(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
|
2021-06-30 00:05:49 +02:00
|
|
|
{
|
2021-07-27 10:27:44 +02:00
|
|
|
*out_is_modified = FALSE;
|
2021-06-30 00:05:49 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-14 15:31:43 +02:00
|
|
|
gboolean
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_from_dbus_fcn_direct_mac_address(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
|
2021-07-14 15:31:43 +02:00
|
|
|
{
|
|
|
|
|
gsize length = 0;
|
|
|
|
|
const guint8 *array;
|
|
|
|
|
|
|
|
|
|
nm_assert(property_info->param_spec);
|
|
|
|
|
nm_assert(property_info->property_type == &nm_sett_info_propert_type_direct_mac_address);
|
|
|
|
|
nm_assert(g_variant_type_equal(property_info->property_type->dbus_type, "ay"));
|
|
|
|
|
nm_assert(
|
|
|
|
|
g_variant_type_equal(g_variant_get_type(value), property_info->property_type->dbus_type));
|
|
|
|
|
nm_assert(property_info->direct_set_string_mac_address_len > 0);
|
|
|
|
|
|
|
|
|
|
array = g_variant_get_fixed_array(value, &length, 1);
|
|
|
|
|
|
2021-07-30 09:04:53 +02:00
|
|
|
if (nm_strdup_reset_take(
|
2021-07-14 15:31:43 +02:00
|
|
|
_nm_setting_get_private(setting, sett_info, property_info->direct_offset),
|
2021-07-27 10:27:44 +02:00
|
|
|
length > 0 ? nm_utils_hwaddr_ntoa(array, length) : NULL)) {
|
2021-07-14 15:31:43 +02:00
|
|
|
g_object_notify_by_pspec(G_OBJECT(setting), property_info->param_spec);
|
2021-07-27 10:27:44 +02:00
|
|
|
} else
|
|
|
|
|
*out_is_modified = FALSE;
|
2021-07-14 15:31:43 +02:00
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-14 15:48:37 +02:00
|
|
|
gboolean
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_from_dbus_fcn_direct(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
|
2021-07-14 15:48:37 +02:00
|
|
|
{
|
|
|
|
|
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; \
|
|
|
|
|
})
|
|
|
|
|
|
2021-07-27 10:27:44 +02:00
|
|
|
*out_is_modified = FALSE;
|
|
|
|
|
|
2021-07-14 15:48:37 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_UINT64:
|
|
|
|
|
{
|
|
|
|
|
const GParamSpecUInt64 *param_spec;
|
|
|
|
|
guint64 * p_val;
|
|
|
|
|
guint64 v;
|
|
|
|
|
|
|
|
|
|
if (g_variant_is_of_type(value, G_VARIANT_TYPE_UINT64))
|
|
|
|
|
v = g_variant_get_uint64(value);
|
|
|
|
|
else {
|
|
|
|
|
if (!_variant_get_value_transform(property_info,
|
|
|
|
|
value,
|
|
|
|
|
G_TYPE_UINT64,
|
|
|
|
|
g_value_get_uint64,
|
|
|
|
|
&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_UINT64(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;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_ENUM:
|
|
|
|
|
{
|
|
|
|
|
const GParamSpecEnum *param_spec;
|
|
|
|
|
int * p_val;
|
|
|
|
|
int v;
|
|
|
|
|
|
|
|
|
|
param_spec = NM_G_PARAM_SPEC_CAST_ENUM(property_info->param_spec);
|
|
|
|
|
|
|
|
|
|
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_FROM_CLASS(param_spec->enum_class),
|
|
|
|
|
g_value_get_flags,
|
|
|
|
|
&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;
|
|
|
|
|
|
|
|
|
|
if (!g_enum_get_value(param_spec->enum_class, v))
|
|
|
|
|
goto out_error_param_spec_validation;
|
|
|
|
|
*p_val = v;
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_FLAGS:
|
|
|
|
|
{
|
|
|
|
|
const GParamSpecFlags *param_spec;
|
|
|
|
|
guint * p_val;
|
|
|
|
|
guint v;
|
|
|
|
|
|
|
|
|
|
param_spec = NM_G_PARAM_SPEC_CAST_FLAGS(property_info->param_spec);
|
|
|
|
|
|
|
|
|
|
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_FROM_CLASS(param_spec->flags_class),
|
|
|
|
|
g_value_get_flags,
|
|
|
|
|
&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;
|
|
|
|
|
|
|
|
|
|
if ((v & param_spec->flags_class->mask) != v)
|
|
|
|
|
goto out_error_param_spec_validation;
|
|
|
|
|
*p_val = v;
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-07-14 15:48:37 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2021-10-27 20:24:17 +02:00
|
|
|
case NM_VALUE_TYPE_BYTES:
|
|
|
|
|
{
|
|
|
|
|
gs_unref_bytes GBytes *v = NULL;
|
|
|
|
|
GBytes ** p_val;
|
|
|
|
|
|
|
|
|
|
if (!g_variant_is_of_type(value, G_VARIANT_TYPE_BYTESTRING))
|
|
|
|
|
goto out_error_wrong_dbus_type;
|
|
|
|
|
|
|
|
|
|
v = nm_g_bytes_new_from_variant_ay(value);
|
|
|
|
|
|
|
|
|
|
p_val = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);
|
|
|
|
|
if (nm_g_bytes_equal0(*p_val, v))
|
|
|
|
|
goto out_unchanged;
|
|
|
|
|
|
|
|
|
|
NM_SWAP(p_val, &v);
|
|
|
|
|
goto out_notify;
|
|
|
|
|
}
|
2021-07-14 15:48:37 +02:00
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
|
|
|
|
|
out_unchanged:
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
out_notify:
|
2021-07-27 10:27:44 +02:00
|
|
|
*out_is_modified = TRUE;
|
2021-07-14 15:48:37 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 00:05:49 +02:00
|
|
|
gboolean
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_from_dbus_fcn_gprop(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil)
|
2021-06-30 00:05:49 +02:00
|
|
|
{
|
|
|
|
|
nm_auto_unset_gvalue GValue object_value = G_VALUE_INIT;
|
|
|
|
|
gs_free_error GError *local = NULL;
|
|
|
|
|
|
|
|
|
|
nm_assert(property_info->param_spec);
|
|
|
|
|
|
|
|
|
|
g_value_init(&object_value, property_info->param_spec->value_type);
|
|
|
|
|
if (!set_property_from_dbus(property_info, value, &object_value)) {
|
|
|
|
|
/* for backward behavior, fail unless best-effort is chosen. */
|
2021-07-27 10:27:44 +02:00
|
|
|
*out_is_modified = FALSE;
|
2021-06-30 00:05:49 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!nm_g_object_set_property(G_OBJECT(setting),
|
|
|
|
|
property_info->param_spec->name,
|
|
|
|
|
&object_value,
|
|
|
|
|
&local)) {
|
2021-07-27 10:27:44 +02:00
|
|
|
*out_is_modified = FALSE;
|
2021-06-30 00:05:49 +02:00
|
|
|
if (!NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
|
|
|
|
|
return TRUE;
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("can not set property: %s"),
|
|
|
|
|
local->message);
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), property_info->name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
static GVariant *
|
2019-04-24 17:41:32 +02:00
|
|
|
property_to_dbus(const NMSettInfoSetting * sett_info,
|
2021-06-29 12:04:00 +02:00
|
|
|
const NMSettInfoProperty * property_info,
|
2019-04-24 17:41:32 +02:00
|
|
|
NMConnection * connection,
|
|
|
|
|
NMSetting * setting,
|
|
|
|
|
NMConnectionSerializationFlags flags,
|
2019-06-27 09:07:16 +02:00
|
|
|
const NMConnectionSerializationOptions *options,
|
2021-06-17 23:13:09 +02:00
|
|
|
gboolean ignore_flags)
|
2014-08-16 10:09:48 -04:00
|
|
|
{
|
2021-06-29 12:04:00 +02:00
|
|
|
GVariant *variant;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(property_info->property_type->dbus_type);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
if (!property_info->property_type->to_dbus_fcn) {
|
|
|
|
|
nm_assert(!property_info->param_spec);
|
2021-06-18 08:59:12 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 22:28:07 +02:00
|
|
|
nm_assert(!property_info->param_spec
|
|
|
|
|
|| NM_FLAGS_HAS(property_info->param_spec->flags, G_PARAM_WRITABLE)
|
|
|
|
|
|| property_info->property_type == &nm_sett_info_propert_type_setting_name);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 22:28:07 +02:00
|
|
|
if (property_info->param_spec && !ignore_flags
|
|
|
|
|
&& !NM_FLAGS_HAS(property_info->param_spec->flags, NM_SETTING_PARAM_TO_DBUS_IGNORE_FLAGS)) {
|
2021-06-29 12:04:00 +02:00
|
|
|
if (NM_FLAGS_HAS(property_info->param_spec->flags, NM_SETTING_PARAM_LEGACY)
|
2019-04-24 17:41:32 +02:00
|
|
|
&& !_nm_utils_is_manager_process)
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
if (NM_FLAGS_HAS(property_info->param_spec->flags, NM_SETTING_PARAM_SECRET)) {
|
2021-03-25 16:39:35 +01:00
|
|
|
NMSettingSecretFlags f = NM_SETTING_SECRET_FLAG_NONE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-03-25 16:39:35 +01:00
|
|
|
if (NM_FLAGS_ANY(flags,
|
|
|
|
|
NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED
|
|
|
|
|
| NM_CONNECTION_SERIALIZE_WITH_SECRETS_SYSTEM_OWNED
|
|
|
|
|
| NM_CONNECTION_SERIALIZE_WITH_SECRETS_NOT_SAVED)) {
|
2021-06-29 12:04:00 +02:00
|
|
|
if (!nm_setting_get_secret_flags(setting,
|
|
|
|
|
property_info->param_spec->name,
|
|
|
|
|
&f,
|
|
|
|
|
NULL))
|
2019-06-15 11:18:46 +02:00
|
|
|
return NULL;
|
|
|
|
|
}
|
2021-03-25 16:39:35 +01:00
|
|
|
|
|
|
|
|
if (!_nm_connection_serialize_secrets(flags, f))
|
|
|
|
|
return NULL;
|
2019-06-15 11:18:46 +02:00
|
|
|
} else {
|
2021-03-25 16:39:35 +01:00
|
|
|
if (!_nm_connection_serialize_non_secret(flags))
|
2019-06-15 11:18:46 +02:00
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
2019-06-15 11:18:46 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
variant = property_info->property_type
|
|
|
|
|
->to_dbus_fcn(sett_info, property_info, connection, setting, flags, options);
|
2021-06-18 08:59:12 +02:00
|
|
|
nm_g_variant_take_ref(variant);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(!variant || g_variant_is_of_type(variant, property_info->property_type->dbus_type));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-24 15:51:04 +02:00
|
|
|
return variant;
|
2014-08-16 10:09:48 -04:00
|
|
|
}
|
|
|
|
|
|
2015-01-15 12:19:06 -05:00
|
|
|
static gboolean
|
2021-06-29 12:04:00 +02:00
|
|
|
set_property_from_dbus(const NMSettInfoProperty *property_info,
|
|
|
|
|
GVariant * src_value,
|
|
|
|
|
GValue * dst_value)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(property_info->param_spec);
|
|
|
|
|
nm_assert(property_info->property_type->dbus_type);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2021-06-30 00:05:49 +02:00
|
|
|
if (property_info->property_type->typdata_from_dbus.gprop_fcn) {
|
libnm: refactor NMSettInfoProperty to save memory for simple properties
In total, we register 447 property informations. Out of these,
326 are plain, GObject property based without special implementations.
The NMSettInfoProperty had all function pointers directly embedded,
currently this amounts to 5 function pointers and the "dbus_type" field.
That means, at runtime we have 326 times trivial implementations with
waste 326*6*8 bytes of NULL pointers. We can compact these by moving
them to a separate structure.
Before:
447 * 5 function pointers
447 * "dbus_type" pointer
= 2682 pointers
After:
447 * 1 pointers (for NMSettInfoProperty.property_type)
89 * 6 pointers (for the distinct NMSettInfoPropertType data)
= 981 pointers
So, in total this saves 13608 byes of runtime memory (on 64 bit arch).
The 89 NMSettInfoPropertType instances are the remaining distinct instances.
Note that every NMSettInfoProperty has a "property_type" pointer, but most of them are
shared. That is because the underlying type and the operations are the same.
Also nice is that the NMSettInfoPropertType are actually constant,
static fields and initialized very early.
This change also makes sense form a design point of view. Previously,
NMSettInfoProperty contained both per-property data (the "name") but
also the behavior. Now, the "behavioral" part is moved to a separate
structure (where it is also shared). That means, the parts that are
concerned with the type of the property (the behavior) are separate
from the actual data of the property.
2019-09-22 08:53:06 +02:00
|
|
|
if (!g_variant_type_equal(g_variant_get_type(src_value),
|
2021-06-29 12:04:00 +02:00
|
|
|
property_info->property_type->dbus_type))
|
2015-01-15 12:19:06 -05:00
|
|
|
return FALSE;
|
2021-06-30 00:05:49 +02:00
|
|
|
property_info->property_type->typdata_from_dbus.gprop_fcn(src_value, dst_value);
|
2021-07-14 13:22:40 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dst_value->g_type == G_TYPE_BYTES) {
|
2015-01-15 12:19:06 -05:00
|
|
|
if (!g_variant_is_of_type(src_value, G_VARIANT_TYPE_BYTESTRING))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2014-11-15 17:34:19 -05:00
|
|
|
_nm_utils_bytes_from_dbus(src_value, dst_value);
|
2021-07-14 13:22:40 +02:00
|
|
|
return TRUE;
|
2015-01-15 12:19:06 -05:00
|
|
|
}
|
|
|
|
|
|
2021-07-14 13:22:40 +02:00
|
|
|
return _nm_property_variant_to_gvalue(src_value, dst_value);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-08-06 19:35:31 -04:00
|
|
|
* _nm_setting_to_dbus:
|
2014-07-24 08:53:33 -04:00
|
|
|
* @setting: the #NMSetting
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
* @connection: the #NMConnection containing @setting
|
2014-08-06 19:35:31 -04:00
|
|
|
* @flags: hash flags, e.g. %NM_CONNECTION_SERIALIZE_ALL
|
2019-06-27 09:07:16 +02:00
|
|
|
* @options: the #NMConnectionSerializationOptions options to control
|
|
|
|
|
* what/how gets serialized.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
2014-08-16 10:09:48 -04:00
|
|
|
* Converts the #NMSetting into a #GVariant of type #NM_VARIANT_TYPE_SETTING
|
|
|
|
|
* mapping each setting property name to a value describing that property,
|
|
|
|
|
* suitable for marshalling over D-Bus or serializing.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
2014-08-16 10:09:48 -04:00
|
|
|
* Returns: (transfer none): a new floating #GVariant describing the setting's
|
|
|
|
|
* properties
|
2014-07-24 08:53:33 -04:00
|
|
|
**/
|
2014-08-16 10:09:48 -04:00
|
|
|
GVariant *
|
2019-06-27 09:07:16 +02:00
|
|
|
_nm_setting_to_dbus(NMSetting * setting,
|
|
|
|
|
NMConnection * connection,
|
|
|
|
|
NMConnectionSerializationFlags flags,
|
|
|
|
|
const NMConnectionSerializationOptions *options)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
NMSettingPrivate * priv;
|
2014-08-16 10:09:48 -04:00
|
|
|
GVariantBuilder builder;
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
const NMSettInfoSetting *sett_info;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint n_properties;
|
|
|
|
|
guint i;
|
|
|
|
|
guint16 j;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
const char *const * gendata_keys;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NULL);
|
|
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
priv = NM_SETTING_GET_PRIVATE(setting);
|
|
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
g_variant_builder_init(&builder, NM_VARIANT_TYPE_SETTING);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2020-05-14 09:16:32 +02:00
|
|
|
n_properties = _nm_setting_option_get_all(setting, &gendata_keys, NULL);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
for (i = 0; i < n_properties; i++) {
|
|
|
|
|
g_variant_builder_add(&builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
gendata_keys[i],
|
|
|
|
|
g_hash_table_lookup(priv->gendata->hash, gendata_keys[i]));
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
2021-06-29 11:44:46 +02:00
|
|
|
for (j = 0; j < sett_info->property_infos_len; j++) {
|
2021-06-29 12:04:00 +02:00
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[j];
|
|
|
|
|
gs_unref_variant GVariant *dbus_value = NULL;
|
2019-01-02 15:54:18 +01:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
dbus_value =
|
|
|
|
|
property_to_dbus(sett_info, property_info, connection, setting, flags, options, FALSE);
|
2014-08-16 10:09:48 -04:00
|
|
|
if (dbus_value) {
|
2021-06-29 12:04:00 +02:00
|
|
|
g_variant_builder_add(&builder, "{sv}", property_info->name, dbus_value);
|
2014-08-16 10:09:48 -04:00
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
return g_variant_builder_end(&builder);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-08-06 19:35:31 -04:00
|
|
|
* _nm_setting_new_from_dbus:
|
2014-07-24 08:53:33 -04:00
|
|
|
* @setting_type: the #NMSetting type which the hash contains properties for
|
2014-08-16 10:09:48 -04:00
|
|
|
* @setting_dict: the #GVariant containing an %NM_VARIANT_TYPE_SETTING dictionary
|
|
|
|
|
* mapping property names to values
|
|
|
|
|
* @connection_dict: the #GVariant containing an %NM_VARIANT_TYPE_CONNECTION
|
|
|
|
|
* dictionary mapping setting names to dictionaries.
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
* @parse_flags: flags to determine behavior during parsing.
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
* @error: location to store error, or %NULL
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Creates a new #NMSetting object and populates that object with the properties
|
2014-08-16 10:09:48 -04:00
|
|
|
* contained in @setting_dict, using each key as the property to set, and each
|
|
|
|
|
* value as the value to set that property to. Setting properties are strongly
|
|
|
|
|
* typed, thus the #GVariantType of the dict value must be correct. See the
|
|
|
|
|
* documentation on each #NMSetting object subclass for the correct property
|
|
|
|
|
* names and value types.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Returns: a new #NMSetting object populated with the properties from the
|
2014-09-15 13:30:07 -04:00
|
|
|
* hash table, or %NULL if @setting_hash could not be deserialized.
|
2014-07-24 08:53:33 -04:00
|
|
|
**/
|
|
|
|
|
NMSetting *
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
_nm_setting_new_from_dbus(GType setting_type,
|
2014-08-16 10:09:48 -04:00
|
|
|
GVariant * setting_dict,
|
|
|
|
|
GVariant * connection_dict,
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
NMSettingParseFlags parse_flags,
|
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.
2014-07-29 18:25:10 -04:00
|
|
|
GError ** error)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2019-05-13 12:22:40 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *keys_keep_variant = NULL;
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
gs_unref_object NMSetting *setting = NULL;
|
|
|
|
|
gs_unref_hashtable GHashTable *keys = NULL;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(G_TYPE_IS_INSTANTIATABLE(setting_type), NULL);
|
2014-08-16 10:09:48 -04:00
|
|
|
g_return_val_if_fail(g_variant_is_of_type(setting_dict, NM_VARIANT_TYPE_SETTING), NULL);
|
|
|
|
|
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
nm_assert(!NM_FLAGS_ANY(parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL));
|
|
|
|
|
nm_assert(!NM_FLAGS_ALL(parse_flags,
|
|
|
|
|
NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT));
|
|
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
/* connection_dict is not technically optional, but some tests in test-general
|
|
|
|
|
* don't bother with it in cases where they know it's not needed.
|
|
|
|
|
*/
|
|
|
|
|
if (connection_dict)
|
|
|
|
|
g_return_val_if_fail(g_variant_is_of_type(connection_dict, NM_VARIANT_TYPE_CONNECTION),
|
|
|
|
|
NULL);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2014-10-21 11:41:44 -04:00
|
|
|
/* Build the setting object from the properties we know about; we assume
|
|
|
|
|
* that any propreties in @setting_dict that we don't know about can
|
|
|
|
|
* either be ignored or else has a backward-compatibility equivalent
|
|
|
|
|
* that we do know about.
|
|
|
|
|
*/
|
2020-11-12 15:57:06 +01:00
|
|
|
setting = g_object_new(setting_type, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
if (NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GVariant * entry, *entry_key;
|
2019-05-13 12:22:40 +02:00
|
|
|
const char * key;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
keys_keep_variant = g_ptr_array_new_with_free_func((GDestroyNotify) g_variant_unref);
|
|
|
|
|
keys = g_hash_table_new(nm_str_hash, g_str_equal);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
g_variant_iter_init(&iter, setting_dict);
|
|
|
|
|
while ((entry = g_variant_iter_next_value(&iter))) {
|
|
|
|
|
entry_key = g_variant_get_child_value(entry, 0);
|
2019-05-13 12:22:40 +02:00
|
|
|
g_ptr_array_add(keys_keep_variant, entry_key);
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
g_variant_unref(entry);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
key = g_variant_get_string(entry_key, NULL);
|
|
|
|
|
if (!g_hash_table_add(keys, (char *) key)) {
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_SETTING,
|
|
|
|
|
_("duplicate property"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), key);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
if (!NM_SETTING_GET_CLASS(setting)
|
|
|
|
|
->init_from_dbus(setting, keys, setting_dict, connection_dict, parse_flags, error))
|
|
|
|
|
return NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
if (NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT) && g_hash_table_size(keys) > 0) {
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
const char * key;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
g_hash_table_iter_init(&iter, keys);
|
|
|
|
|
if (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) {
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("unknown property"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), key);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
return g_steal_pointer(&setting);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-26 22:12:05 +02:00
|
|
|
static gboolean
|
|
|
|
|
_property_set_from_dbus(const NMSettInfoSetting * sett_info,
|
|
|
|
|
const NMSettInfoProperty *property_info,
|
|
|
|
|
NMSetting * setting,
|
|
|
|
|
GVariant * connection_dict,
|
|
|
|
|
GVariant * value,
|
|
|
|
|
NMSettingParseFlags parse_flags,
|
2021-07-27 10:27:44 +02:00
|
|
|
gboolean * out_is_modified,
|
2021-07-26 22:12:05 +02:00
|
|
|
GError ** error)
|
|
|
|
|
{
|
2021-07-27 10:27:44 +02:00
|
|
|
gs_free_error GError *local = NULL;
|
|
|
|
|
NMTernary is_modified = NM_TERNARY_DEFAULT;
|
|
|
|
|
gboolean success;
|
|
|
|
|
|
|
|
|
|
NM_SET_OUT(out_is_modified, FALSE);
|
2021-07-26 22:12:05 +02:00
|
|
|
|
|
|
|
|
if (!property_info->property_type->from_dbus_fcn) {
|
|
|
|
|
nm_assert(!property_info->param_spec);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (property_info->property_type->from_dbus_is_full) {
|
|
|
|
|
/* These hooks perform their own type checking, and can coerce/ignore
|
|
|
|
|
* a value regardless of the D-Bus type. */
|
|
|
|
|
} else if (!g_variant_type_equal(g_variant_get_type(value),
|
|
|
|
|
property_info->property_type->dbus_type)) {
|
|
|
|
|
/* for backward behavior, fail unless best-effort is chosen. */
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 10:27:44 +02:00
|
|
|
success = property_info->property_type->from_dbus_fcn(sett_info,
|
|
|
|
|
property_info,
|
|
|
|
|
setting,
|
|
|
|
|
connection_dict,
|
|
|
|
|
value,
|
|
|
|
|
parse_flags,
|
|
|
|
|
&is_modified,
|
|
|
|
|
&local);
|
|
|
|
|
|
|
|
|
|
/* We allow the from_dbus_fcn() to leave is_modified at NM_TERNARY_DEFAULT,
|
|
|
|
|
* which we assume to also mean that it was modified. That is, we err on the
|
|
|
|
|
* side of assuming modification happened. */
|
|
|
|
|
NM_SET_OUT(out_is_modified, is_modified != FALSE);
|
|
|
|
|
|
|
|
|
|
if (!success) {
|
2021-07-26 22:12:05 +02:00
|
|
|
if (property_info->property_type->from_dbus_is_full) {
|
|
|
|
|
/* the error we received from from_dbus_fcn() should be propagated, even
|
2021-07-27 10:27:44 +02:00
|
|
|
* in non-strict mode. */
|
2021-07-26 22:12:05 +02:00
|
|
|
} else if (!NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
|
|
|
|
|
return TRUE;
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("failed to set property: %s"),
|
|
|
|
|
local->message);
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), property_info->name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
static gboolean
|
|
|
|
|
init_from_dbus(NMSetting * setting,
|
|
|
|
|
GHashTable * keys,
|
|
|
|
|
GVariant * setting_dict,
|
|
|
|
|
GVariant * connection_dict,
|
|
|
|
|
guint /* NMSettingParseFlags */ parse_flags,
|
|
|
|
|
GError ** error)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoSetting *sett_info;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 i;
|
2019-05-13 12:22:40 +02:00
|
|
|
|
|
|
|
|
nm_assert(NM_IS_SETTING(setting));
|
|
|
|
|
nm_assert(!NM_FLAGS_ANY(parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL));
|
|
|
|
|
nm_assert(!NM_FLAGS_ALL(parse_flags,
|
|
|
|
|
NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT));
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
if (sett_info->detail.gendata_info) {
|
|
|
|
|
GHashTable * hash;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
char * key;
|
|
|
|
|
GVariant * val;
|
|
|
|
|
|
|
|
|
|
hash = _gendata_hash(setting, TRUE)->hash;
|
|
|
|
|
|
|
|
|
|
g_variant_iter_init(&iter, setting_dict);
|
|
|
|
|
while (g_variant_iter_next(&iter, "{sv}", &key, &val)) {
|
|
|
|
|
g_hash_table_insert(hash, key, val);
|
2019-05-13 12:22:40 +02:00
|
|
|
if (keys)
|
|
|
|
|
g_hash_table_remove(keys, key);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-14 09:16:32 +02:00
|
|
|
_nm_setting_option_notify(setting, TRUE);
|
2020-05-11 18:48:17 +02:00
|
|
|
|
|
|
|
|
/* Currently, only NMSettingEthtool supports gendata based options, and
|
|
|
|
|
* that one has no other properties (except "name"). That means, we
|
|
|
|
|
* consumed all options above.
|
|
|
|
|
*
|
|
|
|
|
* In the future it may be interesting to have settings that are both
|
|
|
|
|
* based on gendata and regular properties. In that case, we would need
|
|
|
|
|
* to handle this case differently. */
|
|
|
|
|
nm_assert(nm_streq(G_OBJECT_TYPE_NAME(setting), "NMSettingEthtool"));
|
|
|
|
|
nm_assert(sett_info->property_infos_len == 1);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
return TRUE;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2019-01-11 14:10:15 +01:00
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
gs_unref_variant GVariant *value = NULL;
|
|
|
|
|
gs_free_error GError *local = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 22:28:07 +02:00
|
|
|
if (property_info->property_type == &nm_sett_info_propert_type_setting_name)
|
2015-01-15 10:56:02 -05:00
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 22:28:07 +02:00
|
|
|
nm_assert(!property_info->param_spec
|
|
|
|
|
|| NM_FLAGS_HAS(property_info->param_spec->flags, G_PARAM_WRITABLE));
|
|
|
|
|
|
2019-01-11 14:10:15 +01:00
|
|
|
value = g_variant_lookup_value(setting_dict, property_info->name, NULL);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 22:19:52 +02:00
|
|
|
if (!value) {
|
|
|
|
|
if (property_info->property_type->missing_from_dbus_fcn
|
|
|
|
|
&& !property_info->property_type->missing_from_dbus_fcn(setting,
|
|
|
|
|
connection_dict,
|
|
|
|
|
property_info->name,
|
|
|
|
|
parse_flags,
|
|
|
|
|
&local)) {
|
|
|
|
|
if (!NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
|
|
|
|
|
continue;
|
|
|
|
|
g_set_error(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("failed to set property: %s"),
|
|
|
|
|
local->message);
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), property_info->name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (keys)
|
2019-01-11 14:10:15 +01:00
|
|
|
g_hash_table_remove(keys, property_info->name);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-07-26 22:12:05 +02:00
|
|
|
if (!_property_set_from_dbus(sett_info,
|
|
|
|
|
property_info,
|
|
|
|
|
setting,
|
|
|
|
|
connection_dict,
|
|
|
|
|
value,
|
|
|
|
|
parse_flags,
|
2021-07-27 10:27:44 +02:00
|
|
|
NULL,
|
2021-07-26 22:12:05 +02:00
|
|
|
error))
|
|
|
|
|
return FALSE;
|
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when
NetworkManager receives a new connection from a client, the connection
must make sense as a whole (and since NetworkManager service is backward
compatible to the clients and not the other way around, there is no
excuse for sending invalid data to the server).
In other situations, we want a best-effort behavior. Like when
NetworkManager sends a connection to its clients, those clients
want to extract as many properties as they understand, but in order
to be forward compatible against newer server versions, invalid
or unknown properties must be accepted.
Previously, a mixture of both was done. Some issues caused a failure
to create a new NMSetting, other invalid parts were just silently
ignored or triggered a g_warning() in glib.
Now allow for both. When doing strict-validation, be more strict and
reject all unknown properties and catch when the user sets an invalid
argument. On the other hand, allow for a best-effort mode that
effectively cannot fail and will return a new NMSetting instance.
For now, add NMSettingParseFlags so that the caller can choose the
old behavior, strict parsing, or best effort.
This patch doesn't have any externally visible change except that
no more g_warnings will be emitted.
2016-03-18 13:42:50 +01:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2014-11-16 16:13:06 -05:00
|
|
|
/**
|
|
|
|
|
* nm_setting_get_dbus_property_type:
|
|
|
|
|
* @setting: an #NMSetting
|
|
|
|
|
* @property_name: the property of @setting to get the type of
|
|
|
|
|
*
|
|
|
|
|
* Gets the D-Bus marshalling type of a property. @property_name is a D-Bus
|
|
|
|
|
* property name, which may not necessarily be a #GObject property.
|
|
|
|
|
*
|
|
|
|
|
* Returns: the D-Bus marshalling type of @property on @setting.
|
|
|
|
|
*/
|
|
|
|
|
const GVariantType *
|
|
|
|
|
nm_setting_get_dbus_property_type(NMSetting *setting, const char *property_name)
|
|
|
|
|
{
|
2021-06-29 12:04:00 +02:00
|
|
|
const NMSettInfoProperty *property_info;
|
2014-11-16 16:13:06 -05:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NULL);
|
|
|
|
|
g_return_val_if_fail(property_name != NULL, NULL);
|
|
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
property_info =
|
|
|
|
|
_nm_setting_class_get_property_info(NM_SETTING_GET_CLASS(setting), property_name);
|
2019-04-24 15:10:41 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
g_return_val_if_fail(property_info != NULL, NULL);
|
2014-11-16 16:13:06 -05:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(property_info->property_type);
|
|
|
|
|
nm_assert(
|
|
|
|
|
g_variant_type_string_is_valid((const char *) property_info->property_type->dbus_type));
|
2019-04-24 15:51:04 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
return property_info->property_type->dbus_type;
|
2014-11-16 16:13:06 -05:00
|
|
|
}
|
|
|
|
|
|
2014-02-26 10:09:54 +01:00
|
|
|
gboolean
|
|
|
|
|
_nm_setting_get_property(NMSetting *setting, const char *property_name, GValue *value)
|
|
|
|
|
{
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
const NMSettInfoSetting * sett_info;
|
2019-01-10 19:38:36 +01:00
|
|
|
const NMSettInfoProperty *property_info;
|
2014-02-26 10:09:54 +01:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), FALSE);
|
|
|
|
|
g_return_val_if_fail(property_name, FALSE);
|
|
|
|
|
g_return_val_if_fail(value, FALSE);
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
2014-02-26 10:09:54 +01:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (sett_info->detail.gendata_info) {
|
|
|
|
|
GVariant *variant;
|
|
|
|
|
GenData * gendata = _gendata_hash(setting, FALSE);
|
|
|
|
|
|
|
|
|
|
variant = gendata ? g_hash_table_lookup(gendata->hash, property_name) : NULL;
|
|
|
|
|
|
|
|
|
|
if (!variant) {
|
|
|
|
|
g_value_unset(value);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_value_init(value, G_TYPE_VARIANT);
|
|
|
|
|
g_value_set_variant(value, variant);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-10 19:38:36 +01:00
|
|
|
property_info = _nm_sett_info_setting_get_property_info(sett_info, property_name);
|
|
|
|
|
if (!property_info || !property_info->param_spec) {
|
2014-02-26 10:09:54 +01:00
|
|
|
g_value_unset(value);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-10 19:38:36 +01:00
|
|
|
g_value_init(value, property_info->param_spec->value_type);
|
2014-02-26 10:09:54 +01:00
|
|
|
g_object_get_property(G_OBJECT(setting), property_name, value);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
static void
|
2019-01-04 14:37:30 +01:00
|
|
|
_gobject_copy_property(GObject *src, GObject *dst, const char *property_name, GType gtype)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2019-01-04 14:37:30 +01:00
|
|
|
nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
nm_assert(G_IS_OBJECT(src));
|
|
|
|
|
nm_assert(G_IS_OBJECT(dst));
|
|
|
|
|
|
|
|
|
|
g_value_init(&value, gtype);
|
|
|
|
|
g_object_get_property(src, property_name, &value);
|
|
|
|
|
g_object_set_property(dst, property_name, &value);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2019-01-11 15:16:33 +01:00
|
|
|
static void
|
|
|
|
|
duplicate_copy_properties(const NMSettInfoSetting *sett_info, NMSetting *src, NMSetting *dst)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2021-06-29 11:44:46 +02:00
|
|
|
gboolean frozen = FALSE;
|
|
|
|
|
guint16 i;
|
|
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (sett_info->detail.gendata_info) {
|
2019-01-11 15:16:33 +01:00
|
|
|
GenData *gendata = _gendata_hash(src, FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-20 14:01:24 +01:00
|
|
|
nm_assert(!_gendata_hash(dst, FALSE));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (gendata && g_hash_table_size(gendata->hash) > 0) {
|
|
|
|
|
GHashTableIter iter;
|
2019-01-11 15:16:33 +01:00
|
|
|
GHashTable * h = _gendata_hash(dst, TRUE)->hash;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
const char * key;
|
|
|
|
|
GVariant * val;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
g_hash_table_iter_init(&iter, gendata->hash);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) {
|
|
|
|
|
g_hash_table_insert(h, g_strdup(key), g_variant_ref(val));
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 11:44:46 +02:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
|
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 22:28:07 +02:00
|
|
|
if (!property_info->param_spec)
|
|
|
|
|
continue;
|
2021-06-29 11:44:46 +02:00
|
|
|
|
2021-06-29 22:28:07 +02:00
|
|
|
nm_assert(!NM_FLAGS_HAS(property_info->param_spec->flags, G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
|
if (property_info->property_type == &nm_sett_info_propert_type_setting_name)
|
2021-06-29 11:44:46 +02:00
|
|
|
continue;
|
2021-06-29 22:28:07 +02:00
|
|
|
|
|
|
|
|
nm_assert(NM_FLAGS_HAS(property_info->param_spec->flags, G_PARAM_WRITABLE));
|
|
|
|
|
|
|
|
|
|
if (!frozen) {
|
|
|
|
|
g_object_freeze_notify(G_OBJECT(dst));
|
|
|
|
|
frozen = TRUE;
|
2019-01-04 14:37:30 +01:00
|
|
|
}
|
2021-06-29 22:28:07 +02:00
|
|
|
_gobject_copy_property(G_OBJECT(src),
|
|
|
|
|
G_OBJECT(dst),
|
|
|
|
|
property_info->param_spec->name,
|
|
|
|
|
G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec));
|
2019-01-04 14:37:30 +01:00
|
|
|
}
|
2021-06-29 11:44:46 +02:00
|
|
|
|
|
|
|
|
if (frozen)
|
|
|
|
|
g_object_thaw_notify(G_OBJECT(dst));
|
2019-01-11 15:16:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_duplicate:
|
|
|
|
|
* @setting: the #NMSetting to duplicate
|
|
|
|
|
*
|
|
|
|
|
* Duplicates a #NMSetting.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): a new #NMSetting containing the same properties and values as the
|
|
|
|
|
* source #NMSetting
|
|
|
|
|
**/
|
|
|
|
|
NMSetting *
|
|
|
|
|
nm_setting_duplicate(NMSetting *setting)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoSetting *sett_info;
|
|
|
|
|
NMSettingClass * klass;
|
|
|
|
|
NMSetting * dst;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NULL);
|
|
|
|
|
|
|
|
|
|
klass = NM_SETTING_GET_CLASS(setting);
|
|
|
|
|
nm_assert(NM_IS_SETTING_CLASS(klass));
|
|
|
|
|
nm_assert(klass->duplicate_copy_properties);
|
|
|
|
|
|
|
|
|
|
dst = g_object_new(G_TYPE_FROM_CLASS(klass), NULL);
|
|
|
|
|
|
|
|
|
|
sett_info = _nm_setting_class_get_sett_info(klass);
|
|
|
|
|
nm_assert(sett_info);
|
2019-01-04 14:37:30 +01:00
|
|
|
|
2019-01-11 15:16:33 +01:00
|
|
|
klass->duplicate_copy_properties(sett_info, setting, dst);
|
|
|
|
|
return dst;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_get_name:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
*
|
|
|
|
|
* Returns the type name of the #NMSetting object
|
|
|
|
|
*
|
|
|
|
|
* Returns: a string containing the type name of the #NMSetting object,
|
|
|
|
|
* like 'ppp' or 'wireless' or 'wired'.
|
|
|
|
|
**/
|
|
|
|
|
const char *
|
|
|
|
|
nm_setting_get_name(NMSetting *setting)
|
|
|
|
|
{
|
libnm: use NMMetaSettingInfo for tracking setting priority
Previously, each (non abstract) NMSetting class had to register
its name and priority via _nm_register_setting().
Note, that libnm-core.la already links against "nm-meta-setting.c",
which also redundantly keeps track of the settings name and gtype
as well.
Re-use NMMetaSettingInfo also in libnm-core.la, to track this meta
data.
The goal is to get rid of private data structures that track
meta data about NMSetting classes. In this case, "registered_settings"
hash. Instead, we should have one place where all this meta data
is tracked. This was, it is also accessible as internal API,
which can be useful (for keyfile).
Note that NMSettingClass has some overlap with NMMetaSettingInfo.
One difference is, that NMMetaSettingInfo is const, while NMSettingClass
is only initialized during the class_init() method. Appart from that,
it's mostly a matter of taste, whether we attach meta data to
NMSettingClass, to NMMetaSettingInfo, or to a static-array indexed
by NMMetaSettingType.
Note, that previously, _nm_register_setting() was private API. That
means, no user could subclass a functioning NMSetting instance. The same
is still true: NMMetaSettingInfo is internal API and users cannot access
it to create their own NMSetting subclasses. But that is almost desired.
libnm is not designed, to be extensible via subclassing, nor is it
clear why that would be a useful thing to do. One day, we should remove
the NMSetting and NMSettingClass definitions from public headers. Their
only use is subclassing the types, which however does not work.
While libnm-core was linking already against nm-meta-setting.c,
nm_meta_setting_infos was unreferenced. So, this change increases
the binary size of libnm and NetworkManager (1032 bytes). Note however
that roughly the same information was previously allocated at runtime.
2018-07-27 14:08:14 +02:00
|
|
|
const NMMetaSettingInfo *setting_info;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NULL);
|
libnm: use NMMetaSettingInfo for tracking setting priority
Previously, each (non abstract) NMSetting class had to register
its name and priority via _nm_register_setting().
Note, that libnm-core.la already links against "nm-meta-setting.c",
which also redundantly keeps track of the settings name and gtype
as well.
Re-use NMMetaSettingInfo also in libnm-core.la, to track this meta
data.
The goal is to get rid of private data structures that track
meta data about NMSetting classes. In this case, "registered_settings"
hash. Instead, we should have one place where all this meta data
is tracked. This was, it is also accessible as internal API,
which can be useful (for keyfile).
Note that NMSettingClass has some overlap with NMMetaSettingInfo.
One difference is, that NMMetaSettingInfo is const, while NMSettingClass
is only initialized during the class_init() method. Appart from that,
it's mostly a matter of taste, whether we attach meta data to
NMSettingClass, to NMMetaSettingInfo, or to a static-array indexed
by NMMetaSettingType.
Note, that previously, _nm_register_setting() was private API. That
means, no user could subclass a functioning NMSetting instance. The same
is still true: NMMetaSettingInfo is internal API and users cannot access
it to create their own NMSetting subclasses. But that is almost desired.
libnm is not designed, to be extensible via subclassing, nor is it
clear why that would be a useful thing to do. One day, we should remove
the NMSetting and NMSettingClass definitions from public headers. Their
only use is subclassing the types, which however does not work.
While libnm-core was linking already against nm-meta-setting.c,
nm_meta_setting_infos was unreferenced. So, this change increases
the binary size of libnm and NetworkManager (1032 bytes). Note however
that roughly the same information was previously allocated at runtime.
2018-07-27 14:08:14 +02:00
|
|
|
|
|
|
|
|
setting_info = NM_SETTING_GET_CLASS(setting)->setting_info;
|
|
|
|
|
return setting_info ? setting_info->setting_name : NULL;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_verify:
|
|
|
|
|
* @setting: the #NMSetting to verify
|
2014-10-21 22:30:31 -04:00
|
|
|
* @connection: (allow-none): the #NMConnection that @setting came from, or
|
|
|
|
|
* %NULL if @setting is being verified in isolation.
|
2014-07-24 08:53:33 -04:00
|
|
|
* @error: location to store error, or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Validates the setting. Each setting's properties have allowed values, and
|
2014-10-21 22:30:31 -04:00
|
|
|
* some are dependent on other values (hence the need for @connection). The
|
2014-07-24 08:53:33 -04:00
|
|
|
* returned #GError contains information about which property of the setting
|
|
|
|
|
* failed validation, and in what way that property failed validation.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the setting is valid, %FALSE if it is not
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
2014-10-21 22:30:31 -04:00
|
|
|
nm_setting_verify(NMSetting *setting, NMConnection *connection, GError **error)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2014-10-21 22:30:31 -04:00
|
|
|
NMSettingVerifyResult result = _nm_setting_verify(setting, connection, error);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
if (result == NM_SETTING_VERIFY_NORMALIZABLE)
|
|
|
|
|
g_clear_error(error);
|
|
|
|
|
|
|
|
|
|
return result == NM_SETTING_VERIFY_SUCCESS || result == NM_SETTING_VERIFY_NORMALIZABLE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NMSettingVerifyResult
|
2014-10-21 22:30:31 -04:00
|
|
|
_nm_setting_verify(NMSetting *setting, NMConnection *connection, GError **error)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NM_SETTING_VERIFY_ERROR);
|
2014-10-21 22:30:31 -04:00
|
|
|
g_return_val_if_fail(!connection || NM_IS_CONNECTION(connection), NM_SETTING_VERIFY_ERROR);
|
2014-07-24 08:53:33 -04:00
|
|
|
g_return_val_if_fail(!error || *error == NULL, NM_SETTING_VERIFY_ERROR);
|
|
|
|
|
|
|
|
|
|
if (NM_SETTING_GET_CLASS(setting)->verify)
|
2014-10-21 22:30:31 -04:00
|
|
|
return NM_SETTING_GET_CLASS(setting)->verify(setting, connection, error);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
return NM_SETTING_VERIFY_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-10 14:36:20 +01:00
|
|
|
/**
|
|
|
|
|
* nm_setting_verify_secrets:
|
|
|
|
|
* @setting: the #NMSetting to verify secrets in
|
|
|
|
|
* @connection: (allow-none): the #NMConnection that @setting came from, or
|
|
|
|
|
* %NULL if @setting is being verified in isolation.
|
|
|
|
|
* @error: location to store error, or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Verifies the secrets in the setting.
|
|
|
|
|
* The returned #GError contains information about which secret of the setting
|
|
|
|
|
* failed validation, and in what way that secret failed validation.
|
|
|
|
|
* The secret validation is done separately from main setting validation, because
|
|
|
|
|
* in some cases connection failure is not desired just for the secrets.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the setting secrets are valid, %FALSE if they are not
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.2
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_verify_secrets(NMSetting *setting, NMConnection *connection, GError **error)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NM_SETTING_VERIFY_ERROR);
|
|
|
|
|
g_return_val_if_fail(!connection || NM_IS_CONNECTION(connection), NM_SETTING_VERIFY_ERROR);
|
|
|
|
|
g_return_val_if_fail(!error || *error == NULL, NM_SETTING_VERIFY_ERROR);
|
|
|
|
|
|
|
|
|
|
if (NM_SETTING_GET_CLASS(setting)->verify_secrets)
|
|
|
|
|
return NM_SETTING_GET_CLASS(setting)->verify_secrets(setting, connection, error);
|
|
|
|
|
|
|
|
|
|
return NM_SETTING_VERIFY_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_setting_verify_secret_string(const char *str,
|
|
|
|
|
const char *setting_name,
|
|
|
|
|
const char *property,
|
|
|
|
|
GError ** error)
|
|
|
|
|
{
|
|
|
|
|
if (str && !*str) {
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("property is empty"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", setting_name, property);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
gboolean
|
|
|
|
|
_nm_setting_should_compare_secret_property(NMSetting * setting,
|
|
|
|
|
NMSetting * other,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
NMSettingCompareFlags flags)
|
|
|
|
|
{
|
|
|
|
|
NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
|
NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_SETTING(setting));
|
|
|
|
|
nm_assert(!other || G_OBJECT_TYPE(setting) == G_OBJECT_TYPE(other));
|
|
|
|
|
|
|
|
|
|
/* secret_name must be a valid secret for @setting. */
|
|
|
|
|
nm_assert(nm_setting_get_secret_flags(setting, secret_name, NULL, NULL));
|
|
|
|
|
|
|
|
|
|
if (!NM_FLAGS_ANY(flags,
|
|
|
|
|
NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS
|
|
|
|
|
| NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
nm_setting_get_secret_flags(setting, secret_name, &a_secret_flags, NULL);
|
|
|
|
|
if (other) {
|
|
|
|
|
if (!nm_setting_get_secret_flags(other, secret_name, &b_secret_flags, NULL)) {
|
|
|
|
|
/* secret-name may not be a valid secret for @other. That is fine, we ignore that
|
|
|
|
|
* and treat @b_secret_flags as NM_SETTING_SECRET_FLAG_NONE.
|
|
|
|
|
*
|
|
|
|
|
* This can happen with VPN secrets, where the caller knows that @secret_name
|
|
|
|
|
* is a secret for setting, but it may not be a secret for @other. Accept that.
|
|
|
|
|
*
|
|
|
|
|
* Mark @other as missing. */
|
|
|
|
|
other = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* when @setting has the secret-flags that should be ignored,
|
2019-10-10 10:20:50 +02:00
|
|
|
* we skip the comparison if:
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
*
|
|
|
|
|
* - @other is not present,
|
|
|
|
|
* - @other does not have a secret named @secret_name
|
|
|
|
|
* - @other also has the secret flat to be ignored.
|
|
|
|
|
*
|
|
|
|
|
* This makes the check symmetric (aside the fact that @setting must
|
2019-01-11 17:07:03 -02:00
|
|
|
* have the secret while @other may not -- which is asymmetric). */
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
|
|
|
|
|
&& NM_FLAGS_HAS(a_secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED)
|
|
|
|
|
&& (!other || NM_FLAGS_HAS(b_secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
|
|
|
|
|
&& NM_FLAGS_HAS(a_secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED)
|
|
|
|
|
&& (!other || NM_FLAGS_HAS(b_secret_flags, NM_SETTING_SECRET_FLAG_NOT_SAVED)))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:23:16 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2021-06-29 18:12:56 +02:00
|
|
|
gboolean
|
|
|
|
|
_nm_setting_compare_flags_check(const GParamSpec * param_spec,
|
|
|
|
|
NMSettingCompareFlags flags,
|
|
|
|
|
NMSetting * set_a,
|
|
|
|
|
NMSetting * set_b)
|
|
|
|
|
{
|
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_FUZZY)
|
|
|
|
|
&& NM_FLAGS_ANY(param_spec->flags, NM_SETTING_PARAM_FUZZY_IGNORE | NM_SETTING_PARAM_SECRET))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
|
|
|
|
|
&& !NM_FLAGS_HAS(param_spec->flags, NM_SETTING_PARAM_INFERRABLE))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY)
|
|
|
|
|
&& NM_FLAGS_HAS(param_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
|
|
|
|
|
&& NM_FLAGS_HAS(param_spec->flags, NM_SETTING_PARAM_SECRET))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
if (NM_FLAGS_HAS(param_spec->flags, NM_SETTING_PARAM_SECRET)
|
|
|
|
|
&& !_nm_setting_should_compare_secret_property(set_a, set_b, param_spec->name, flags))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 17:03:37 +02:00
|
|
|
NMTernary
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_compare_fcn_ignore(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil)
|
2021-06-29 17:03:37 +02:00
|
|
|
{
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 18:18:06 +02:00
|
|
|
NMTernary
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_compare_fcn_direct(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil)
|
2021-06-29 18:18:06 +02:00
|
|
|
{
|
|
|
|
|
gconstpointer p_a;
|
|
|
|
|
gconstpointer p_b;
|
|
|
|
|
|
2021-07-13 18:09:13 +02:00
|
|
|
nm_assert(NM_IN_SET(property_info->property_type->to_dbus_fcn,
|
|
|
|
|
_nm_setting_property_to_dbus_fcn_direct,
|
|
|
|
|
_nm_setting_property_to_dbus_fcn_direct_mac_address));
|
2021-06-29 18:18:06 +02:00
|
|
|
|
|
|
|
|
if (!property_info->param_spec)
|
|
|
|
|
return nm_assert_unreachable_val(NM_TERNARY_DEFAULT);
|
|
|
|
|
|
|
|
|
|
if (!_nm_setting_compare_flags_check(property_info->param_spec, flags, set_a, set_b))
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
|
|
|
|
|
|
|
|
|
if (!set_b)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
p_a = _nm_setting_get_private(set_a, sett_info, property_info->direct_offset);
|
|
|
|
|
p_b = _nm_setting_get_private(set_b, sett_info, property_info->direct_offset);
|
|
|
|
|
|
|
|
|
|
switch (property_info->property_type->direct_type) {
|
|
|
|
|
case NM_VALUE_TYPE_BOOL:
|
|
|
|
|
return *((const bool *) p_a) == *((const bool *) p_b);
|
2021-07-13 22:56:05 +02:00
|
|
|
case NM_VALUE_TYPE_INT32:
|
|
|
|
|
return *((const gint32 *) p_a) == *((const gint32 *) p_b);
|
2021-06-29 18:18:06 +02:00
|
|
|
case NM_VALUE_TYPE_UINT32:
|
|
|
|
|
return *((const guint32 *) p_a) == *((const guint32 *) p_b);
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_UINT64:
|
|
|
|
|
return *((const guint64 *) p_a) == *((const guint64 *) p_b);
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_ENUM:
|
|
|
|
|
return *((const int *) p_a) == *((const int *) p_b);
|
2021-10-20 10:53:39 +02:00
|
|
|
case NM_VALUE_TYPE_FLAGS:
|
|
|
|
|
return *((const guint *) p_a) == *((const guint *) p_b);
|
2021-06-29 18:18:06 +02:00
|
|
|
case NM_VALUE_TYPE_STRING:
|
|
|
|
|
return nm_streq0(*((const char *const *) p_a), *((const char *const *) p_b));
|
2021-10-27 20:24:17 +02:00
|
|
|
case NM_VALUE_TYPE_BYTES:
|
|
|
|
|
return nm_g_bytes_equal0(*((const GBytes *const *) p_a), *((const GBytes *const *) p_b));
|
2021-06-29 18:18:06 +02:00
|
|
|
default:
|
|
|
|
|
return nm_assert_unreachable_val(TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:23:16 +02:00
|
|
|
NMTernary
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_property_compare_fcn_default(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2021-06-29 18:18:06 +02:00
|
|
|
nm_assert(property_info->property_type->direct_type == NM_VALUE_TYPE_NONE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 18:18:06 +02:00
|
|
|
if (!property_info->param_spec)
|
2021-06-29 17:03:37 +02:00
|
|
|
return nm_assert_unreachable_val(NM_TERNARY_DEFAULT);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 18:18:06 +02:00
|
|
|
if (!_nm_setting_compare_flags_check(property_info->param_spec, flags, set_a, set_b))
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
return NM_TERNARY_DEFAULT;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 18:18:06 +02:00
|
|
|
if (!set_b)
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
{
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
gs_unref_variant GVariant *value1 = NULL;
|
|
|
|
|
gs_unref_variant GVariant *value2 = NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-06-27 09:07:16 +02:00
|
|
|
value1 = property_to_dbus(sett_info,
|
2021-06-29 12:04:00 +02:00
|
|
|
property_info,
|
2019-06-27 09:07:16 +02:00
|
|
|
con_a,
|
|
|
|
|
set_a,
|
|
|
|
|
NM_CONNECTION_SERIALIZE_ALL,
|
|
|
|
|
NULL,
|
|
|
|
|
TRUE);
|
|
|
|
|
value2 = property_to_dbus(sett_info,
|
2021-06-29 12:04:00 +02:00
|
|
|
property_info,
|
2019-06-27 09:07:16 +02:00
|
|
|
con_b,
|
|
|
|
|
set_b,
|
|
|
|
|
NM_CONNECTION_SERIALIZE_ALL,
|
|
|
|
|
NULL,
|
|
|
|
|
TRUE);
|
2021-06-29 18:18:06 +02:00
|
|
|
return nm_property_compare(value1, value2) == 0;
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
static NMTernary
|
2021-06-29 12:04:00 +02:00
|
|
|
_compare_property(const NMSettInfoSetting * sett_info,
|
|
|
|
|
const NMSettInfoProperty *property_info,
|
|
|
|
|
NMConnection * con_a,
|
|
|
|
|
NMSetting * set_a,
|
|
|
|
|
NMConnection * con_b,
|
|
|
|
|
NMSetting * set_b,
|
|
|
|
|
NMSettingCompareFlags flags)
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
{
|
|
|
|
|
NMTernary compare_result;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
nm_assert(sett_info);
|
|
|
|
|
nm_assert(NM_IS_SETTING_CLASS(sett_info->setting_class));
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(property_info);
|
2019-04-25 10:17:47 +02:00
|
|
|
nm_assert(NM_SETTING_GET_CLASS(set_a) == sett_info->setting_class);
|
|
|
|
|
nm_assert(!set_b || NM_SETTING_GET_CLASS(set_b) == sett_info->setting_class);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 14:23:16 +02:00
|
|
|
compare_result = property_info->property_type
|
|
|
|
|
->compare_fcn(sett_info, property_info, con_a, set_a, con_b, set_b, flags);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 14:23:16 +02:00
|
|
|
nm_assert_is_ternary(compare_result);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
/* check that the inferable flag and the GObject property flag corresponds. */
|
2021-06-29 12:04:00 +02:00
|
|
|
nm_assert(!NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE) || !property_info->param_spec
|
|
|
|
|
|| NM_FLAGS_HAS(property_info->param_spec->flags, NM_SETTING_PARAM_INFERRABLE)
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
|| compare_result == NM_TERNARY_DEFAULT);
|
|
|
|
|
|
2019-10-10 10:20:50 +02:00
|
|
|
#if NM_MORE_ASSERTS > 10
|
2021-06-29 14:23:16 +02:00
|
|
|
/* assert that compare_fcn() is symeric. */
|
|
|
|
|
nm_assert(
|
|
|
|
|
!set_b
|
|
|
|
|
|| compare_result
|
|
|
|
|
== property_info->property_type
|
|
|
|
|
->compare_fcn(sett_info, property_info, con_b, set_b, con_a, set_a, flags));
|
2019-10-10 10:20:50 +02:00
|
|
|
#endif
|
|
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
return compare_result;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_compare:
|
|
|
|
|
* @a: a #NMSetting
|
|
|
|
|
* @b: a second #NMSetting to compare with the first
|
|
|
|
|
* @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
|
|
|
|
|
*
|
|
|
|
|
* Compares two #NMSetting objects for similarity, with comparison behavior
|
|
|
|
|
* modified by a set of flags. See the documentation for #NMSettingCompareFlags
|
|
|
|
|
* for a description of each flag's behavior.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the comparison succeeds, %FALSE if it does not
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_compare(NMSetting *a, NMSetting *b, NMSettingCompareFlags flags)
|
2019-04-25 10:17:47 +02:00
|
|
|
{
|
|
|
|
|
return _nm_setting_compare(NULL, a, NULL, b, flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_setting_compare(NMConnection * con_a,
|
|
|
|
|
NMSetting * a,
|
|
|
|
|
NMConnection * con_b,
|
|
|
|
|
NMSetting * b,
|
|
|
|
|
NMSettingCompareFlags flags)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
const NMSettInfoSetting *sett_info;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 i;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(a), FALSE);
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(b), FALSE);
|
|
|
|
|
|
2019-04-25 10:17:47 +02:00
|
|
|
nm_assert(!con_a || NM_IS_CONNECTION(con_a));
|
|
|
|
|
nm_assert(!con_b || NM_IS_CONNECTION(con_b));
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/* First check that both have the same type */
|
|
|
|
|
if (G_OBJECT_TYPE(a) != G_OBJECT_TYPE(b))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(a));
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
if (sett_info->detail.gendata_info) {
|
|
|
|
|
GenData *a_gendata = _gendata_hash(a, FALSE);
|
|
|
|
|
GenData *b_gendata = _gendata_hash(b, FALSE);
|
|
|
|
|
|
2020-11-02 18:27:26 +01:00
|
|
|
return nm_utils_hashtable_equal(a_gendata ? a_gendata->hash : NULL,
|
|
|
|
|
b_gendata ? b_gendata->hash : NULL,
|
|
|
|
|
TRUE,
|
|
|
|
|
g_variant_equal);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-04 10:49:50 +01:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2021-06-29 12:04:00 +02:00
|
|
|
if (_compare_property(sett_info, &sett_info->property_infos[i], con_a, a, con_b, b, flags)
|
|
|
|
|
== NM_TERNARY_FALSE)
|
2014-07-24 08:53:33 -04:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
static void
|
|
|
|
|
_setting_diff_add_result(GHashTable *results, const char *prop_name, NMSettingDiffResult r)
|
|
|
|
|
{
|
|
|
|
|
void *p;
|
|
|
|
|
|
|
|
|
|
if (r == NM_SETTING_DIFF_RESULT_UNKNOWN)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (g_hash_table_lookup_extended(results, prop_name, NULL, &p)) {
|
|
|
|
|
if (!NM_FLAGS_ALL((guint) r, GPOINTER_TO_UINT(p)))
|
|
|
|
|
g_hash_table_insert(results,
|
|
|
|
|
g_strdup(prop_name),
|
|
|
|
|
GUINT_TO_POINTER(((guint) r) | GPOINTER_TO_UINT(p)));
|
|
|
|
|
} else
|
|
|
|
|
g_hash_table_insert(results, g_strdup(prop_name), GUINT_TO_POINTER(r));
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_setting_diff:
|
|
|
|
|
* @a: a #NMSetting
|
|
|
|
|
* @b: a second #NMSetting to compare with the first
|
|
|
|
|
* @flags: compare flags, e.g. %NM_SETTING_COMPARE_FLAG_EXACT
|
2014-07-04 13:26:57 -04:00
|
|
|
* @invert_results: this parameter is used internally by libnm and should
|
2014-07-24 08:53:33 -04:00
|
|
|
* be set to %FALSE. If %TRUE inverts the meaning of the #NMSettingDiffResult.
|
|
|
|
|
* @results: (inout) (transfer full) (element-type utf8 guint32): if the
|
|
|
|
|
* settings differ, on return a hash table mapping the differing keys to one or
|
|
|
|
|
* more %NMSettingDiffResult values OR-ed together. If the settings do not
|
|
|
|
|
* differ, any hash table passed in is unmodified. If no hash table is passed
|
|
|
|
|
* in and the settings differ, a new one is created and returned.
|
|
|
|
|
*
|
|
|
|
|
* Compares two #NMSetting objects for similarity, with comparison behavior
|
|
|
|
|
* modified by a set of flags. See the documentation for #NMSettingCompareFlags
|
|
|
|
|
* for a description of each flag's behavior. If the settings differ, the keys
|
|
|
|
|
* of each setting that differ from the other are added to @results, mapped to
|
|
|
|
|
* one or more #NMSettingDiffResult values.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the settings contain the same values, %FALSE if they do not
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_diff(NMSetting * a,
|
|
|
|
|
NMSetting * b,
|
|
|
|
|
NMSettingCompareFlags flags,
|
|
|
|
|
gboolean invert_results,
|
|
|
|
|
GHashTable ** results)
|
2019-04-25 10:17:47 +02:00
|
|
|
{
|
|
|
|
|
return _nm_setting_diff(NULL, a, NULL, b, flags, invert_results, results);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_setting_diff(NMConnection * con_a,
|
|
|
|
|
NMSetting * a,
|
|
|
|
|
NMConnection * con_b,
|
|
|
|
|
NMSetting * b,
|
|
|
|
|
NMSettingCompareFlags flags,
|
|
|
|
|
gboolean invert_results,
|
|
|
|
|
GHashTable ** results)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
const NMSettInfoSetting *sett_info;
|
2014-07-24 08:53:33 -04:00
|
|
|
NMSettingDiffResult a_result = NM_SETTING_DIFF_RESULT_IN_A;
|
|
|
|
|
NMSettingDiffResult b_result = NM_SETTING_DIFF_RESULT_IN_B;
|
2014-02-26 11:26:25 +01:00
|
|
|
NMSettingDiffResult a_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT;
|
|
|
|
|
NMSettingDiffResult b_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT;
|
2014-07-24 08:53:33 -04:00
|
|
|
gboolean results_created = FALSE;
|
2017-10-26 13:25:54 +02:00
|
|
|
gboolean compared_any = FALSE;
|
libnm: fix the return value of nm_setting_diff() if a results hash was given
Previously, nm_setting_diff() would return !(*results), that means,
if the caller passed in a hash table (empty or not), the return value
would always be FALSE, indicating a difference.
That is not documented, and makes no sense.
The return value, should solely indicate whether some difference was
found. The only convenience is, if nm_setting_diff() created a hash
table internally and no difference was found, it would destroy
it again, without returning it to the caller.
2017-10-26 13:49:03 +02:00
|
|
|
gboolean diff_found = FALSE;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
g_return_val_if_fail(results != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(a), FALSE);
|
|
|
|
|
if (b) {
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(b), FALSE);
|
|
|
|
|
g_return_val_if_fail(G_OBJECT_TYPE(a) == G_OBJECT_TYPE(b), FALSE);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-04-25 10:17:47 +02:00
|
|
|
nm_assert(!con_a || NM_IS_CONNECTION(con_a));
|
|
|
|
|
nm_assert(!con_b || NM_IS_CONNECTION(con_b));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-02-26 11:26:25 +01:00
|
|
|
if ((flags
|
|
|
|
|
& (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT
|
|
|
|
|
| NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT))
|
|
|
|
|
== (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT
|
|
|
|
|
| NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT)) {
|
|
|
|
|
/* conflicting flags: default to WITH_DEFAULT (clearing NO_DEFAULT). */
|
|
|
|
|
flags &= ~NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/* If the caller is calling this function in a pattern like this to get
|
|
|
|
|
* complete diffs:
|
|
|
|
|
*
|
|
|
|
|
* nm_setting_diff (A, B, FALSE, &results);
|
|
|
|
|
* nm_setting_diff (B, A, TRUE, &results);
|
|
|
|
|
*
|
|
|
|
|
* and wants us to invert the results so that the second invocation comes
|
|
|
|
|
* out correctly, do that here.
|
|
|
|
|
*/
|
|
|
|
|
if (invert_results) {
|
|
|
|
|
a_result = NM_SETTING_DIFF_RESULT_IN_B;
|
|
|
|
|
b_result = NM_SETTING_DIFF_RESULT_IN_A;
|
2014-02-26 11:26:25 +01:00
|
|
|
a_result_default = NM_SETTING_DIFF_RESULT_IN_B_DEFAULT;
|
|
|
|
|
b_result_default = NM_SETTING_DIFF_RESULT_IN_A_DEFAULT;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
if (*results == NULL) {
|
2017-11-15 16:06:43 +01:00
|
|
|
*results = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, NULL);
|
2014-07-24 08:53:33 -04:00
|
|
|
results_created = TRUE;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(a));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (sett_info->detail.gendata_info) {
|
|
|
|
|
const char * key;
|
|
|
|
|
GVariant * val, *val2;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
GenData * a_gendata = _gendata_hash(a, FALSE);
|
|
|
|
|
GenData * b_gendata = b ? _gendata_hash(b, FALSE) : NULL;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (!a_gendata || !b_gendata) {
|
|
|
|
|
if (a_gendata || b_gendata) {
|
|
|
|
|
NMSettingDiffResult one_sided_result;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
one_sided_result = a_gendata ? a_result : b_result;
|
|
|
|
|
g_hash_table_iter_init(&iter, a_gendata ? a_gendata->hash : b_gendata->hash);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &key, NULL)) {
|
|
|
|
|
diff_found = TRUE;
|
|
|
|
|
_setting_diff_add_result(*results, key, one_sided_result);
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
} else {
|
|
|
|
|
g_hash_table_iter_init(&iter, a_gendata->hash);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) {
|
2018-10-04 09:38:58 +02:00
|
|
|
val2 = g_hash_table_lookup(b_gendata->hash, key);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
compared_any = TRUE;
|
|
|
|
|
if (!val2 || !g_variant_equal(val, val2)) {
|
|
|
|
|
diff_found = TRUE;
|
|
|
|
|
_setting_diff_add_result(*results, key, a_result);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_hash_table_iter_init(&iter, b_gendata->hash);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) {
|
2018-10-04 09:38:58 +02:00
|
|
|
val2 = g_hash_table_lookup(a_gendata->hash, key);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
compared_any = TRUE;
|
|
|
|
|
if (!val2 || !g_variant_equal(val, val2)) {
|
|
|
|
|
diff_found = TRUE;
|
|
|
|
|
_setting_diff_add_result(*results, key, b_result);
|
2020-09-28 16:03:33 +02:00
|
|
|
}
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2019-01-04 10:49:50 +01:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2021-06-29 12:04:00 +02:00
|
|
|
NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
|
|
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
NMTernary compare_result;
|
|
|
|
|
GParamSpec * prop_spec;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
compare_result = _compare_property(sett_info, property_info, con_a, a, con_b, b, flags);
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (compare_result == NM_TERNARY_DEFAULT)
|
2019-01-04 10:49:50 +01:00
|
|
|
continue;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (NM_FLAGS_ANY(flags,
|
|
|
|
|
NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS
|
|
|
|
|
| NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
|
|
|
|
|
&& b && compare_result == NM_TERNARY_FALSE) {
|
|
|
|
|
/* we have setting @b and the property is not the same. But we also are instructed
|
|
|
|
|
* to ignore secrets based on the flags.
|
|
|
|
|
*
|
|
|
|
|
* Note that compare_property() called with two settings will ignore secrets
|
|
|
|
|
* based on the flags, but it will do so if *both* settings have the flag we
|
2019-01-11 17:07:03 -02:00
|
|
|
* look for. So that is symmetric behavior and good.
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
*
|
|
|
|
|
* But for the purpose of diff(), we do a asymmetric comparison because and
|
|
|
|
|
* we want to skip testing the property if setting @a alone indicates to do
|
|
|
|
|
* so.
|
|
|
|
|
*
|
|
|
|
|
* We need to double-check whether the property should be ignored by
|
|
|
|
|
* looking at @a alone. */
|
2021-06-29 12:04:00 +02:00
|
|
|
if (_compare_property(sett_info, property_info, con_a, a, NULL, NULL, flags)
|
2019-04-25 10:17:47 +02:00
|
|
|
== NM_TERNARY_DEFAULT)
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
compared_any = TRUE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 12:04:00 +02:00
|
|
|
prop_spec = property_info->param_spec;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (b) {
|
|
|
|
|
if (compare_result == NM_TERNARY_FALSE) {
|
|
|
|
|
if (prop_spec) {
|
|
|
|
|
gboolean a_is_default, b_is_default;
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
g_value_init(&value, prop_spec->value_type);
|
|
|
|
|
g_object_get_property(G_OBJECT(a), prop_spec->name, &value);
|
|
|
|
|
a_is_default = g_param_value_defaults(prop_spec, &value);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
g_value_reset(&value);
|
|
|
|
|
g_object_get_property(G_OBJECT(b), prop_spec->name, &value);
|
|
|
|
|
b_is_default = g_param_value_defaults(prop_spec, &value);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
g_value_unset(&value);
|
|
|
|
|
if (!NM_FLAGS_HAS(flags,
|
|
|
|
|
NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)) {
|
|
|
|
|
if (!a_is_default)
|
|
|
|
|
r |= a_result;
|
|
|
|
|
if (!b_is_default)
|
|
|
|
|
r |= b_result;
|
|
|
|
|
} else {
|
|
|
|
|
r |= a_result | b_result;
|
|
|
|
|
if (a_is_default)
|
|
|
|
|
r |= a_result_default;
|
|
|
|
|
if (b_is_default)
|
|
|
|
|
r |= b_result_default;
|
|
|
|
|
}
|
|
|
|
|
} else
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
r |= a_result | b_result;
|
|
|
|
|
}
|
|
|
|
|
} else if ((flags
|
|
|
|
|
& (NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT
|
|
|
|
|
| NM_SETTING_COMPARE_FLAG_DIFF_RESULT_NO_DEFAULT))
|
|
|
|
|
== 0)
|
|
|
|
|
r = a_result; /* only in A */
|
|
|
|
|
else {
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (prop_spec) {
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
g_value_init(&value, prop_spec->value_type);
|
|
|
|
|
g_object_get_property(G_OBJECT(a), prop_spec->name, &value);
|
|
|
|
|
if (!g_param_value_defaults(prop_spec, &value))
|
|
|
|
|
r |= a_result;
|
|
|
|
|
else if (flags & NM_SETTING_COMPARE_FLAG_DIFF_RESULT_WITH_DEFAULT)
|
|
|
|
|
r |= a_result | a_result_default;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
g_value_unset(&value);
|
|
|
|
|
} else
|
|
|
|
|
r |= a_result;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (r != NM_SETTING_DIFF_RESULT_UNKNOWN) {
|
|
|
|
|
diff_found = TRUE;
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
_setting_diff_add_result(*results, property_info->name, r);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2017-10-26 13:25:54 +02:00
|
|
|
if (!compared_any && !b) {
|
|
|
|
|
/* special case: the setting has no properties, and the opposite
|
|
|
|
|
* setting @b is not given. The settings differ, and we signal that
|
|
|
|
|
* by returning an empty results hash. */
|
libnm: fix the return value of nm_setting_diff() if a results hash was given
Previously, nm_setting_diff() would return !(*results), that means,
if the caller passed in a hash table (empty or not), the return value
would always be FALSE, indicating a difference.
That is not documented, and makes no sense.
The return value, should solely indicate whether some difference was
found. The only convenience is, if nm_setting_diff() created a hash
table internally and no difference was found, it would destroy
it again, without returning it to the caller.
2017-10-26 13:49:03 +02:00
|
|
|
diff_found = TRUE;
|
2017-10-26 13:25:54 +02:00
|
|
|
}
|
|
|
|
|
|
libnm: fix the return value of nm_setting_diff() if a results hash was given
Previously, nm_setting_diff() would return !(*results), that means,
if the caller passed in a hash table (empty or not), the return value
would always be FALSE, indicating a difference.
That is not documented, and makes no sense.
The return value, should solely indicate whether some difference was
found. The only convenience is, if nm_setting_diff() created a hash
table internally and no difference was found, it would destroy
it again, without returning it to the caller.
2017-10-26 13:49:03 +02:00
|
|
|
if (diff_found) {
|
|
|
|
|
/* if there is a difference, we always return FALSE. It also means, we might
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
* have allocated a new @results hash, and return it to the caller. */
|
libnm: fix the return value of nm_setting_diff() if a results hash was given
Previously, nm_setting_diff() would return !(*results), that means,
if the caller passed in a hash table (empty or not), the return value
would always be FALSE, indicating a difference.
That is not documented, and makes no sense.
The return value, should solely indicate whether some difference was
found. The only convenience is, if nm_setting_diff() created a hash
table internally and no difference was found, it would destroy
it again, without returning it to the caller.
2017-10-26 13:49:03 +02:00
|
|
|
return FALSE;
|
|
|
|
|
} else {
|
|
|
|
|
if (results_created) {
|
|
|
|
|
/* the allocated hash is unused. Clear it again. */
|
|
|
|
|
g_hash_table_destroy(*results);
|
|
|
|
|
*results = NULL;
|
|
|
|
|
} else {
|
|
|
|
|
/* we found no diff, and return false. However, the input
|
|
|
|
|
* @result is returned unmodified. */
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 08:10:14 +01:00
|
|
|
static void
|
|
|
|
|
enumerate_values(const NMSettInfoProperty *property_info,
|
|
|
|
|
NMSetting * setting,
|
|
|
|
|
NMSettingValueIterFn func,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
if (!property_info->param_spec)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec));
|
|
|
|
|
g_object_get_property(G_OBJECT(setting), property_info->param_spec->name, &value);
|
|
|
|
|
func(setting,
|
|
|
|
|
property_info->param_spec->name,
|
|
|
|
|
&value,
|
|
|
|
|
property_info->param_spec->flags,
|
|
|
|
|
user_data);
|
|
|
|
|
g_value_unset(&value);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/**
|
|
|
|
|
* nm_setting_enumerate_values:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @func: (scope call): user-supplied function called for each property of the setting
|
|
|
|
|
* @user_data: user data passed to @func at each invocation
|
|
|
|
|
*
|
|
|
|
|
* Iterates over each property of the #NMSetting object, calling the supplied
|
|
|
|
|
* user function for each property.
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_enumerate_values(NMSetting *setting, NMSettingValueIterFn func, gpointer user_data)
|
|
|
|
|
{
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
const NMSettInfoSetting *sett_info;
|
|
|
|
|
guint i;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 j;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
g_return_if_fail(NM_IS_SETTING(setting));
|
|
|
|
|
g_return_if_fail(func != NULL);
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
if (sett_info->detail.gendata_info) {
|
|
|
|
|
const char *const *names;
|
2019-01-04 10:49:50 +01:00
|
|
|
guint n_properties;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
/* the properties of this setting are not real GObject properties.
|
|
|
|
|
* Hence, this API makes little sense (or does it?). Still, call
|
|
|
|
|
* @func with each value. */
|
2020-05-14 09:16:32 +02:00
|
|
|
n_properties = _nm_setting_option_get_all(setting, &names, NULL);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (n_properties > 0) {
|
|
|
|
|
gs_strfreev char **keys = g_strdupv((char **) names);
|
|
|
|
|
GHashTable * h = _gendata_hash(setting, FALSE)->hash;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
for (i = 0; i < n_properties; i++) {
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
GVariant *val = g_hash_table_lookup(h, keys[i]);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (!val) {
|
|
|
|
|
/* was deleted in the meantime? Skip */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
g_value_init(&value, G_TYPE_VARIANT);
|
|
|
|
|
g_value_set_variant(&value, val);
|
|
|
|
|
/* call it will GParamFlags 0. It shall indicate that this
|
|
|
|
|
* is not a "real" GObject property. */
|
|
|
|
|
func(setting, keys[i], &value, 0, user_data);
|
|
|
|
|
g_value_unset(&value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-06-29 11:44:46 +02:00
|
|
|
for (j = 0; j < sett_info->property_infos_len; j++) {
|
2019-01-21 08:10:14 +01:00
|
|
|
NM_SETTING_GET_CLASS(setting)->enumerate_values(
|
2021-06-29 11:44:46 +02:00
|
|
|
_nm_sett_info_property_info_get_sorted(sett_info, j),
|
2019-01-21 08:10:14 +01:00
|
|
|
setting,
|
|
|
|
|
func,
|
|
|
|
|
user_data);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 08:46:41 +01:00
|
|
|
static gboolean
|
|
|
|
|
aggregate(NMSetting *setting, int type_i, gpointer arg)
|
2019-01-04 11:28:27 +01:00
|
|
|
{
|
2019-01-21 08:46:41 +01:00
|
|
|
NMConnectionAggregateType type = type_i;
|
2019-01-04 11:28:27 +01:00
|
|
|
const NMSettInfoSetting * sett_info;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-21 08:46:41 +01:00
|
|
|
nm_assert(NM_IN_SET(type,
|
|
|
|
|
NM_CONNECTION_AGGREGATE_ANY_SECRETS,
|
|
|
|
|
NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
2019-01-04 11:28:27 +01:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2019-01-09 17:03:34 +01:00
|
|
|
const NMSettInfoProperty * property_info = &sett_info->property_infos[i];
|
|
|
|
|
GParamSpec * prop_spec = property_info->param_spec;
|
2019-01-04 11:28:27 +01:00
|
|
|
nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
|
|
|
|
|
NMSettingSecretFlags secret_flags;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-09 17:03:34 +01:00
|
|
|
if (!prop_spec || !NM_FLAGS_HAS(prop_spec->flags, NM_SETTING_PARAM_SECRET)) {
|
|
|
|
|
nm_assert(!nm_setting_get_secret_flags(setting, property_info->name, NULL, NULL));
|
2019-01-04 11:28:27 +01:00
|
|
|
continue;
|
2019-01-09 17:03:34 +01:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-09 17:03:34 +01:00
|
|
|
/* for the moment, all aggregate types only care about secrets. */
|
|
|
|
|
nm_assert(nm_setting_get_secret_flags(setting, property_info->name, NULL, NULL));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-04 11:28:27 +01:00
|
|
|
switch (type) {
|
|
|
|
|
case NM_CONNECTION_AGGREGATE_ANY_SECRETS:
|
|
|
|
|
g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(prop_spec));
|
|
|
|
|
g_object_get_property(G_OBJECT(setting), prop_spec->name, &value);
|
|
|
|
|
if (!g_param_value_defaults(prop_spec, &value)) {
|
|
|
|
|
*((gboolean *) arg) = TRUE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-04 11:28:27 +01:00
|
|
|
case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS:
|
|
|
|
|
if (!nm_setting_get_secret_flags(setting, prop_spec->name, &secret_flags, NULL))
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
|
|
|
|
|
*((gboolean *) arg) = TRUE;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-04 11:28:27 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 08:46:41 +01:00
|
|
|
/**
|
|
|
|
|
* _nm_setting_aggregate:
|
|
|
|
|
* @setting: the #NMSetting to aggregate.
|
|
|
|
|
* @type: the #NMConnectionAggregateType aggregate type.
|
|
|
|
|
* @arg: the in/out arguments for aggregation. They depend on @type.
|
|
|
|
|
*
|
|
|
|
|
* This is the implementation detail of _nm_connection_aggregate(). It
|
|
|
|
|
* makes no sense to call this function directly outside of _nm_connection_aggregate().
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if afterwards the aggregation is complete. That means,
|
|
|
|
|
* the only caller _nm_connection_aggregate() will not visit other settings
|
|
|
|
|
* after a setting returns %TRUE (indicating that there is nothing further
|
|
|
|
|
* to aggregate). Note that is very different from the boolean return
|
|
|
|
|
* argument of _nm_connection_aggregate(), which serves a different purpose.
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_setting_aggregate(NMSetting *setting, NMConnectionAggregateType type, gpointer arg)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), FALSE);
|
|
|
|
|
g_return_val_if_fail(arg, FALSE);
|
|
|
|
|
g_return_val_if_fail(NM_IN_SET(type,
|
|
|
|
|
NM_CONNECTION_AGGREGATE_ANY_SECRETS,
|
|
|
|
|
NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS),
|
|
|
|
|
FALSE);
|
|
|
|
|
|
|
|
|
|
return NM_SETTING_GET_CLASS(setting)->aggregate(setting, type, arg);
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
static gboolean
|
2019-01-13 21:23:02 +01:00
|
|
|
clear_secrets(const NMSettInfoSetting * sett_info,
|
2021-06-29 12:04:00 +02:00
|
|
|
const NMSettInfoProperty * property_info,
|
2019-01-13 21:23:02 +01:00
|
|
|
NMSetting * setting,
|
|
|
|
|
NMSettingClearSecretsWithFlagsFn func,
|
|
|
|
|
gpointer user_data)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
|
|
|
|
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
|
2021-06-29 12:04:00 +02:00
|
|
|
GParamSpec * param_spec = property_info->param_spec;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-13 21:23:02 +01:00
|
|
|
if (!param_spec)
|
|
|
|
|
return FALSE;
|
libnm-util: don't assert in nm_setting_get_secret_flags() and avoid assertion in agent_secrets_done_cb()
When secret providers return the connection hash in GetSecrets(),
this hash should only contain secrets. However, some providers also
return non-secret properties.
for_each_secret() iterated over all entries of the @secrets hash
and triggered the assertion in nm_setting_get_secret_flags() (see
below).
NM should not assert against user provided input. Change
nm_setting_get_secret_flags() to silently return FALSE, if the property
is not a secret.
Indeed, handling of secrets is very different for NMSettingVpn and
others. Hence nm_setting_get_secret_flags() has only an inconsistent
behavior and we have to fix all call sites to do the right thing
(depending on whether we have a VPN setting or not).
Now for_each_secret() checks whether the property is a secret
without hitting the assertion. Adjust all other calls of
nm_setting_get_secret_flags(), to anticipate non-secret flags and
assert/warn where appropriate.
Also, agent_secrets_done_cb() clears now all non-secrets properties
from the hash, using the new argument @remove_non_secrets when calling
for_each_secret().
#0 0x0000003370c504e9 in g_logv () from /lib64/libglib-2.0.so.0
#1 0x0000003370c5063f in g_log () from /lib64/libglib-2.0.so.0
#2 0x00007fa4b0c1c156 in get_secret_flags (setting=0x1e3ac60, secret_name=0x1ea9180 "security", verify_secret=1, out_flags=0x7fff7507857c, error=0x0) at nm-setting.c:1091
#3 0x00007fa4b0c1c2b2 in nm_setting_get_secret_flags (setting=0x1e3ac60, secret_name=0x1ea9180 "security", out_flags=0x7fff7507857c, error=0x0) at nm-setting.c:1124
#4 0x0000000000463d03 in for_each_secret (connection=0x1deb2f0, secrets=0x1e9f860, callback=0x464f1b <has_system_owned_secrets>, callback_data=0x7fff7507865c) at settings/nm-settings-connection.c:203
#5 0x000000000046525f in agent_secrets_done_cb (manager=0x1dddf50, call_id=1, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_username=0x1e51710 "thom", agent_has_modify=1, setting_name=0x1e91f90 "802-11-wireless-security",
flags=NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION, secrets=0x1e9f860, error=0x0, user_data=0x1deb2f0, other_data2=0x477d61 <get_secrets_cb>, other_data3=0x1ea92a0) at settings/nm-settings-connection.c:757
#6 0x00000000004dc4fd in get_complete_cb (parent=0x1ea6300, secrets=0x1e9f860, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_username=0x1e51710 "thom", error=0x0, user_data=0x1dddf50) at settings/nm-agent-manager.c:1139
#7 0x00000000004dab54 in req_complete_success (req=0x1ea6300, secrets=0x1e9f860, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_uname=0x1e51710 "thom") at settings/nm-agent-manager.c:502
#8 0x00000000004db86e in get_done_cb (agent=0x1e89530, call_id=0x1, secrets=0x1e9f860, error=0x0, user_data=0x1ea6300) at settings/nm-agent-manager.c:856
#9 0x00000000004de9d0 in get_callback (proxy=0x1e47530, call=0x1, user_data=0x1ea10f0) at settings/nm-secret-agent.c:267
#10 0x000000337380cad2 in complete_pending_call_and_unlock () from /lib64/libdbus-1.so.3
#11 0x000000337380fdc1 in dbus_connection_dispatch () from /lib64/libdbus-1.so.3
#12 0x000000342800ad65 in message_queue_dispatch () from /lib64/libdbus-glib-1.so.2
#13 0x0000003370c492a6 in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#14 0x0000003370c49628 in g_main_context_iterate.isra.24 () from /lib64/libglib-2.0.so.0
#15 0x0000003370c49a3a in g_main_loop_run () from /lib64/libglib-2.0.so.0
#16 0x000000000042e5c6 in main (argc=1, argv=0x7fff75078e88) at main.c:644
Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-02-23 17:03:01 +01:00
|
|
|
|
2019-01-13 21:23:02 +01:00
|
|
|
if (!NM_FLAGS_HAS(param_spec->flags, NM_SETTING_PARAM_SECRET))
|
|
|
|
|
return FALSE;
|
libnm-util: don't assert in nm_setting_get_secret_flags() and avoid assertion in agent_secrets_done_cb()
When secret providers return the connection hash in GetSecrets(),
this hash should only contain secrets. However, some providers also
return non-secret properties.
for_each_secret() iterated over all entries of the @secrets hash
and triggered the assertion in nm_setting_get_secret_flags() (see
below).
NM should not assert against user provided input. Change
nm_setting_get_secret_flags() to silently return FALSE, if the property
is not a secret.
Indeed, handling of secrets is very different for NMSettingVpn and
others. Hence nm_setting_get_secret_flags() has only an inconsistent
behavior and we have to fix all call sites to do the right thing
(depending on whether we have a VPN setting or not).
Now for_each_secret() checks whether the property is a secret
without hitting the assertion. Adjust all other calls of
nm_setting_get_secret_flags(), to anticipate non-secret flags and
assert/warn where appropriate.
Also, agent_secrets_done_cb() clears now all non-secrets properties
from the hash, using the new argument @remove_non_secrets when calling
for_each_secret().
#0 0x0000003370c504e9 in g_logv () from /lib64/libglib-2.0.so.0
#1 0x0000003370c5063f in g_log () from /lib64/libglib-2.0.so.0
#2 0x00007fa4b0c1c156 in get_secret_flags (setting=0x1e3ac60, secret_name=0x1ea9180 "security", verify_secret=1, out_flags=0x7fff7507857c, error=0x0) at nm-setting.c:1091
#3 0x00007fa4b0c1c2b2 in nm_setting_get_secret_flags (setting=0x1e3ac60, secret_name=0x1ea9180 "security", out_flags=0x7fff7507857c, error=0x0) at nm-setting.c:1124
#4 0x0000000000463d03 in for_each_secret (connection=0x1deb2f0, secrets=0x1e9f860, callback=0x464f1b <has_system_owned_secrets>, callback_data=0x7fff7507865c) at settings/nm-settings-connection.c:203
#5 0x000000000046525f in agent_secrets_done_cb (manager=0x1dddf50, call_id=1, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_username=0x1e51710 "thom", agent_has_modify=1, setting_name=0x1e91f90 "802-11-wireless-security",
flags=NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION, secrets=0x1e9f860, error=0x0, user_data=0x1deb2f0, other_data2=0x477d61 <get_secrets_cb>, other_data3=0x1ea92a0) at settings/nm-settings-connection.c:757
#6 0x00000000004dc4fd in get_complete_cb (parent=0x1ea6300, secrets=0x1e9f860, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_username=0x1e51710 "thom", error=0x0, user_data=0x1dddf50) at settings/nm-agent-manager.c:1139
#7 0x00000000004dab54 in req_complete_success (req=0x1ea6300, secrets=0x1e9f860, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_uname=0x1e51710 "thom") at settings/nm-agent-manager.c:502
#8 0x00000000004db86e in get_done_cb (agent=0x1e89530, call_id=0x1, secrets=0x1e9f860, error=0x0, user_data=0x1ea6300) at settings/nm-agent-manager.c:856
#9 0x00000000004de9d0 in get_callback (proxy=0x1e47530, call=0x1, user_data=0x1ea10f0) at settings/nm-secret-agent.c:267
#10 0x000000337380cad2 in complete_pending_call_and_unlock () from /lib64/libdbus-1.so.3
#11 0x000000337380fdc1 in dbus_connection_dispatch () from /lib64/libdbus-1.so.3
#12 0x000000342800ad65 in message_queue_dispatch () from /lib64/libdbus-glib-1.so.2
#13 0x0000003370c492a6 in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#14 0x0000003370c49628 in g_main_context_iterate.isra.24 () from /lib64/libglib-2.0.so.0
#15 0x0000003370c49a3a in g_main_loop_run () from /lib64/libglib-2.0.so.0
#16 0x000000000042e5c6 in main (argc=1, argv=0x7fff75078e88) at main.c:644
Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-02-23 17:03:01 +01:00
|
|
|
|
2019-01-13 21:23:02 +01:00
|
|
|
if (func) {
|
|
|
|
|
if (!nm_setting_get_secret_flags(setting, param_spec->name, &flags, NULL))
|
|
|
|
|
nm_assert_not_reached();
|
|
|
|
|
if (!func(setting, param_spec->name, flags, user_data))
|
|
|
|
|
return FALSE;
|
|
|
|
|
} else
|
|
|
|
|
nm_assert(nm_setting_get_secret_flags(setting, param_spec->name, NULL, NULL));
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-13 21:23:02 +01:00
|
|
|
{
|
|
|
|
|
nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
g_value_init(&value, param_spec->value_type);
|
|
|
|
|
g_object_get_property(G_OBJECT(setting), param_spec->name, &value);
|
|
|
|
|
if (g_param_value_defaults(param_spec, &value))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
g_param_value_set_default(param_spec, &value);
|
|
|
|
|
g_object_set_property(G_OBJECT(setting), param_spec->name, &value);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
2019-01-13 21:23:02 +01:00
|
|
|
return TRUE;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-01-13 20:47:05 +01:00
|
|
|
* _nm_setting_clear_secrets:
|
2014-07-24 08:53:33 -04:00
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @func: (scope call): function to be called to determine whether a
|
|
|
|
|
* specific secret should be cleared or not
|
|
|
|
|
* @user_data: caller-supplied data passed to @func
|
|
|
|
|
*
|
|
|
|
|
* Clears and frees secrets determined by @func.
|
2014-10-07 08:46:36 +02:00
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the setting changed at all
|
2014-07-24 08:53:33 -04:00
|
|
|
**/
|
|
|
|
|
gboolean
|
2019-01-13 20:47:05 +01:00
|
|
|
_nm_setting_clear_secrets(NMSetting * setting,
|
|
|
|
|
NMSettingClearSecretsWithFlagsFn func,
|
|
|
|
|
gpointer user_data)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2019-01-04 10:49:50 +01:00
|
|
|
const NMSettInfoSetting *sett_info;
|
2014-07-24 08:53:33 -04:00
|
|
|
gboolean changed = FALSE;
|
2021-07-27 14:11:33 +02:00
|
|
|
NMSettingClass * klass;
|
2021-06-29 11:44:46 +02:00
|
|
|
guint16 i;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), FALSE);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2021-07-27 14:11:33 +02:00
|
|
|
klass = NM_SETTING_GET_CLASS(setting);
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
2019-01-04 10:49:50 +01:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2021-07-27 14:11:33 +02:00
|
|
|
changed |= klass->clear_secrets(sett_info,
|
|
|
|
|
&sett_info->property_infos[i],
|
|
|
|
|
setting,
|
|
|
|
|
func,
|
|
|
|
|
user_data);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-10-07 08:46:36 +02:00
|
|
|
* _nm_setting_need_secrets:
|
2014-07-24 08:53:33 -04:00
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
*
|
|
|
|
|
* Returns an array of property names for each secret which may be required
|
|
|
|
|
* to make a successful connection. The returned hints are only intended as a
|
|
|
|
|
* guide to what secrets may be required, because in some circumstances, there
|
|
|
|
|
* is no way to conclusively determine exactly which secrets are needed.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer container) (element-type utf8): a #GPtrArray containing
|
|
|
|
|
* the property names of secrets of the #NMSetting which may be required; the
|
|
|
|
|
* caller owns the array and must free it with g_ptr_array_free(), but must not
|
|
|
|
|
* free the elements.
|
|
|
|
|
**/
|
|
|
|
|
GPtrArray *
|
2014-10-07 08:46:36 +02:00
|
|
|
_nm_setting_need_secrets(NMSetting *setting)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
|
|
|
|
GPtrArray *secrets = NULL;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NULL);
|
|
|
|
|
|
|
|
|
|
if (NM_SETTING_GET_CLASS(setting)->need_secrets)
|
|
|
|
|
secrets = NM_SETTING_GET_CLASS(setting)->need_secrets(setting);
|
|
|
|
|
|
|
|
|
|
return secrets;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
2014-08-16 10:09:48 -04:00
|
|
|
update_one_secret(NMSetting *setting, const char *key, GVariant *value, GError **error)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
libnm: use from_dbus_fcn() property callback from update_one_secret()
Our handling of properties is relatively complicated. We should have
clear code paths and responsibilities who calls who.
There is from_dbus_fcn() callback to implement parsing a GVariant and
set the property in NMSetting. This is called via:
- _nm_setting_new_from_dbus()
- init_from_dbus()
- _property_set_from_dbus()
Then, one of the from_dbus_fcn() implementations is
_nm_setting_property_from_dbus_fcn_gprop(), which calls
set_property_from_dbus(). That one sets the property using GObject
setter. That's good and a clear code path.
However, set_property_from_dbus() was also called via
- _nm_setting_update_secrets()
- klass->update_one_secret()
- nm-setting.c:update_one_secret()
- set_property_from_dbus()
Meaning, there is a different code path to set_property_from_dbus(),
which bypasses from_dbus_fcn(). That is highly undesirable, because
it should be clear how a property setter gets implemented, and this
way, potentially two different implementations were used.
Refactor nm-setting.c:update_one_secret() to use
_property_set_from_dbus() instead. This behaves potentially differently
for properties like NM_SETTING_ADSL_PASSWORD, which is implemented as
a "direct" property, where from_dbus_fcn() setter no longer uses g_object_set().
This should not make a difference in practice, and in any case, now the
code paths are unified.
2021-07-26 22:42:25 +02:00
|
|
|
const NMSettInfoSetting * sett_info;
|
|
|
|
|
const NMSettInfoProperty *property_info;
|
|
|
|
|
gboolean is_modified;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: use from_dbus_fcn() property callback from update_one_secret()
Our handling of properties is relatively complicated. We should have
clear code paths and responsibilities who calls who.
There is from_dbus_fcn() callback to implement parsing a GVariant and
set the property in NMSetting. This is called via:
- _nm_setting_new_from_dbus()
- init_from_dbus()
- _property_set_from_dbus()
Then, one of the from_dbus_fcn() implementations is
_nm_setting_property_from_dbus_fcn_gprop(), which calls
set_property_from_dbus(). That one sets the property using GObject
setter. That's good and a clear code path.
However, set_property_from_dbus() was also called via
- _nm_setting_update_secrets()
- klass->update_one_secret()
- nm-setting.c:update_one_secret()
- set_property_from_dbus()
Meaning, there is a different code path to set_property_from_dbus(),
which bypasses from_dbus_fcn(). That is highly undesirable, because
it should be clear how a property setter gets implemented, and this
way, potentially two different implementations were used.
Refactor nm-setting.c:update_one_secret() to use
_property_set_from_dbus() instead. This behaves potentially differently
for properties like NM_SETTING_ADSL_PASSWORD, which is implemented as
a "direct" property, where from_dbus_fcn() setter no longer uses g_object_set().
This should not make a difference in practice, and in any case, now the
code paths are unified.
2021-07-26 22:42:25 +02:00
|
|
|
sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting));
|
|
|
|
|
property_info = _nm_sett_info_setting_get_property_info(sett_info, key);
|
|
|
|
|
if (!property_info) {
|
libnm-core: merge NMSetting*Error into NMConnectionError
Each setting type was defining its own error type, but most of them
had exactly the same three errors ("unknown", "missing property", and
"invalid property"), and none of the other values was of much use
programmatically anyway.
So, this commit merges NMSettingError, NMSettingAdslError, etc, all
into NMConnectionError. (The reason for merging into NMConnectionError
rather than NMSettingError is that we also already have
"NMSettingsError", for errors related to the settings service, so
"NMConnectionError" is a less-confusable name for settings/connection
errors than "NMSettingError".)
Also, make sure that all of the affected error messages are localized,
and (where appropriate) prefix them with the relevant property name.
Renamed error codes:
NM_SETTING_ERROR_PROPERTY_NOT_FOUND -> NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND
NM_SETTING_ERROR_PROPERTY_NOT_SECRET -> NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET
Remapped error codes:
NM_SETTING_*_ERROR_MISSING_PROPERTY -> NM_CONNECTION_ERROR_MISSING_PROPERTY
NM_SETTING_*_ERROR_INVALID_PROPERTY -> NM_CONNECTION_ERROR_INVALID_PROPERTY
NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH -> NM_CONNECTION_ERROR_INVALID_PROPERTY
NM_SETTING_BLUETOOTH_ERROR_TYPE_SETTING_NOT_FOUND -> NM_CONNECTION_ERROR_INVALID_SETTING
NM_SETTING_BOND_ERROR_INVALID_OPTION -> NM_CONNECTION_ERROR_INVALID_PROPERTY
NM_SETTING_BOND_ERROR_MISSING_OPTION -> NM_CONNECTION_ERROR_MISSING_PROPERTY
NM_SETTING_CONNECTION_ERROR_TYPE_SETTING_NOT_FOUND -> NM_CONNECTION_ERROR_MISSING_SETTING
NM_SETTING_CONNECTION_ERROR_SLAVE_SETTING_NOT_FOUND -> NM_CONNECTION_ERROR_MISSING_SETTING
NM_SETTING_IP4_CONFIG_ERROR_NOT_ALLOWED_FOR_METHOD -> NM_CONNECTION_ERROR_INVALID_PROPERTY
NM_SETTING_IP6_CONFIG_ERROR_NOT_ALLOWED_FOR_METHOD -> NM_CONNECTION_ERROR_INVALID_PROPERTY
NM_SETTING_VLAN_ERROR_INVALID_PARENT -> NM_CONNECTION_ERROR_INVALID_PROPERTY
NM_SETTING_WIRELESS_SECURITY_ERROR_MISSING_802_1X_SETTING -> NM_CONNECTION_ERROR_MISSING_SETTING
NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_802_1X -> NM_CONNECTION_ERROR_INVALID_PROPERTY
NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME -> NM_CONNECTION_ERROR_MISSING_PROPERTY
NM_SETTING_WIRELESS_SECURITY_ERROR_SHARED_KEY_REQUIRES_WEP -> NM_CONNECTION_ERROR_INVALID_PROPERTY
NM_SETTING_WIRELESS_ERROR_CHANNEL_REQUIRES_BAND -> NM_CONNECTION_ERROR_MISSING_PROPERTY
Dropped error codes (were previously defined but unused):
NM_SETTING_CDMA_ERROR_MISSING_SERIAL_SETTING
NM_SETTING_CONNECTION_ERROR_IP_CONFIG_NOT_ALLOWED
NM_SETTING_GSM_ERROR_MISSING_SERIAL_SETTING
NM_SETTING_PPP_ERROR_REQUIRE_MPPE_NOT_ALLOWED
NM_SETTING_PPPOE_ERROR_MISSING_PPP_SETTING
NM_SETTING_SERIAL_ERROR_MISSING_PPP_SETTING
NM_SETTING_WIRELESS_ERROR_MISSING_SECURITY_SETTING
2014-10-20 13:52:23 -04:00
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND,
|
|
|
|
|
_("secret not found"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), key);
|
2014-07-24 08:53:33 -04:00
|
|
|
return NM_SETTING_UPDATE_SECRET_ERROR;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: use from_dbus_fcn() property callback from update_one_secret()
Our handling of properties is relatively complicated. We should have
clear code paths and responsibilities who calls who.
There is from_dbus_fcn() callback to implement parsing a GVariant and
set the property in NMSetting. This is called via:
- _nm_setting_new_from_dbus()
- init_from_dbus()
- _property_set_from_dbus()
Then, one of the from_dbus_fcn() implementations is
_nm_setting_property_from_dbus_fcn_gprop(), which calls
set_property_from_dbus(). That one sets the property using GObject
setter. That's good and a clear code path.
However, set_property_from_dbus() was also called via
- _nm_setting_update_secrets()
- klass->update_one_secret()
- nm-setting.c:update_one_secret()
- set_property_from_dbus()
Meaning, there is a different code path to set_property_from_dbus(),
which bypasses from_dbus_fcn(). That is highly undesirable, because
it should be clear how a property setter gets implemented, and this
way, potentially two different implementations were used.
Refactor nm-setting.c:update_one_secret() to use
_property_set_from_dbus() instead. This behaves potentially differently
for properties like NM_SETTING_ADSL_PASSWORD, which is implemented as
a "direct" property, where from_dbus_fcn() setter no longer uses g_object_set().
This should not make a difference in practice, and in any case, now the
code paths are unified.
2021-07-26 22:42:25 +02:00
|
|
|
if (!property_info->param_spec
|
|
|
|
|
|| !NM_FLAGS_HAS(property_info->param_spec->flags, NM_SETTING_PARAM_SECRET)) {
|
|
|
|
|
/* Silently ignore non-secrets */
|
2014-07-24 08:53:33 -04:00
|
|
|
return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
|
|
|
|
|
}
|
2014-08-16 10:09:48 -04:00
|
|
|
|
libnm: use from_dbus_fcn() property callback from update_one_secret()
Our handling of properties is relatively complicated. We should have
clear code paths and responsibilities who calls who.
There is from_dbus_fcn() callback to implement parsing a GVariant and
set the property in NMSetting. This is called via:
- _nm_setting_new_from_dbus()
- init_from_dbus()
- _property_set_from_dbus()
Then, one of the from_dbus_fcn() implementations is
_nm_setting_property_from_dbus_fcn_gprop(), which calls
set_property_from_dbus(). That one sets the property using GObject
setter. That's good and a clear code path.
However, set_property_from_dbus() was also called via
- _nm_setting_update_secrets()
- klass->update_one_secret()
- nm-setting.c:update_one_secret()
- set_property_from_dbus()
Meaning, there is a different code path to set_property_from_dbus(),
which bypasses from_dbus_fcn(). That is highly undesirable, because
it should be clear how a property setter gets implemented, and this
way, potentially two different implementations were used.
Refactor nm-setting.c:update_one_secret() to use
_property_set_from_dbus() instead. This behaves potentially differently
for properties like NM_SETTING_ADSL_PASSWORD, which is implemented as
a "direct" property, where from_dbus_fcn() setter no longer uses g_object_set().
This should not make a difference in practice, and in any case, now the
code paths are unified.
2021-07-26 22:42:25 +02:00
|
|
|
if (!_property_set_from_dbus(sett_info,
|
|
|
|
|
property_info,
|
|
|
|
|
setting,
|
|
|
|
|
NULL,
|
|
|
|
|
value,
|
|
|
|
|
NM_SETTING_PARSE_FLAGS_BEST_EFFORT,
|
|
|
|
|
&is_modified,
|
|
|
|
|
NULL)) {
|
|
|
|
|
/* Silently ignore errors. */
|
|
|
|
|
}
|
2014-08-16 10:09:48 -04:00
|
|
|
|
libnm: use from_dbus_fcn() property callback from update_one_secret()
Our handling of properties is relatively complicated. We should have
clear code paths and responsibilities who calls who.
There is from_dbus_fcn() callback to implement parsing a GVariant and
set the property in NMSetting. This is called via:
- _nm_setting_new_from_dbus()
- init_from_dbus()
- _property_set_from_dbus()
Then, one of the from_dbus_fcn() implementations is
_nm_setting_property_from_dbus_fcn_gprop(), which calls
set_property_from_dbus(). That one sets the property using GObject
setter. That's good and a clear code path.
However, set_property_from_dbus() was also called via
- _nm_setting_update_secrets()
- klass->update_one_secret()
- nm-setting.c:update_one_secret()
- set_property_from_dbus()
Meaning, there is a different code path to set_property_from_dbus(),
which bypasses from_dbus_fcn(). That is highly undesirable, because
it should be clear how a property setter gets implemented, and this
way, potentially two different implementations were used.
Refactor nm-setting.c:update_one_secret() to use
_property_set_from_dbus() instead. This behaves potentially differently
for properties like NM_SETTING_ADSL_PASSWORD, which is implemented as
a "direct" property, where from_dbus_fcn() setter no longer uses g_object_set().
This should not make a difference in practice, and in any case, now the
code paths are unified.
2021-07-26 22:42:25 +02:00
|
|
|
return is_modified ? NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED
|
|
|
|
|
: NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2014-08-04 11:23:11 -04:00
|
|
|
* _nm_setting_update_secrets:
|
2014-07-24 08:53:33 -04:00
|
|
|
* @setting: the #NMSetting
|
2014-08-16 10:09:48 -04:00
|
|
|
* @secrets: a #GVariant of type #NM_VARIANT_TYPE_SETTING, mapping property
|
|
|
|
|
* names to secrets.
|
2014-07-24 08:53:33 -04:00
|
|
|
* @error: location to store error, or %NULL
|
|
|
|
|
*
|
2014-08-16 10:09:48 -04:00
|
|
|
* Update the setting's secrets, given a dictionary of secrets intended for that
|
2014-07-24 08:53:33 -04:00
|
|
|
* setting (deserialized from D-Bus for example).
|
|
|
|
|
*
|
2014-08-04 11:23:11 -04:00
|
|
|
* Returns: an #NMSettingUpdateSecretResult
|
2014-07-24 08:53:33 -04:00
|
|
|
**/
|
|
|
|
|
NMSettingUpdateSecretResult
|
2014-08-16 10:09:48 -04:00
|
|
|
_nm_setting_update_secrets(NMSetting *setting, GVariant *secrets, GError **error)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2014-08-16 10:09:48 -04:00
|
|
|
GVariantIter iter;
|
|
|
|
|
const char * secret_key;
|
|
|
|
|
GVariant * secret_value;
|
2014-07-24 08:53:33 -04:00
|
|
|
GError * tmp_error = NULL;
|
|
|
|
|
NMSettingUpdateSecretResult result = NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NM_SETTING_UPDATE_SECRET_ERROR);
|
2014-08-16 10:09:48 -04:00
|
|
|
g_return_val_if_fail(g_variant_is_of_type(secrets, NM_VARIANT_TYPE_SETTING),
|
|
|
|
|
NM_SETTING_UPDATE_SECRET_ERROR);
|
2014-07-24 08:53:33 -04:00
|
|
|
if (error)
|
|
|
|
|
g_return_val_if_fail(*error == NULL, NM_SETTING_UPDATE_SECRET_ERROR);
|
|
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
g_variant_iter_init(&iter, secrets);
|
|
|
|
|
while (g_variant_iter_next(&iter, "{&sv}", &secret_key, &secret_value)) {
|
2014-07-24 08:53:33 -04:00
|
|
|
int success;
|
|
|
|
|
|
|
|
|
|
success = NM_SETTING_GET_CLASS(setting)->update_one_secret(setting,
|
|
|
|
|
secret_key,
|
|
|
|
|
secret_value,
|
|
|
|
|
&tmp_error);
|
2019-01-30 12:36:13 +01:00
|
|
|
nm_assert(!((success == NM_SETTING_UPDATE_SECRET_ERROR) ^ (!!tmp_error)));
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
g_variant_unref(secret_value);
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
if (success == NM_SETTING_UPDATE_SECRET_ERROR) {
|
|
|
|
|
g_propagate_error(error, tmp_error);
|
|
|
|
|
return NM_SETTING_UPDATE_SECRET_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (success == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED)
|
|
|
|
|
result = NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-31 09:38:58 +01:00
|
|
|
static void
|
|
|
|
|
for_each_secret(NMSetting * setting,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
GVariant * val,
|
|
|
|
|
gboolean remove_non_secrets,
|
|
|
|
|
_NMConnectionForEachSecretFunc callback,
|
|
|
|
|
gpointer callback_data,
|
|
|
|
|
GVariantBuilder * setting_builder)
|
|
|
|
|
{
|
|
|
|
|
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
|
|
|
|
|
|
if (!nm_setting_get_secret_flags(setting, secret_name, &secret_flags, NULL)) {
|
|
|
|
|
if (!remove_non_secrets)
|
|
|
|
|
g_variant_builder_add(setting_builder, "{sv}", secret_name, val);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (callback(secret_flags, callback_data))
|
|
|
|
|
g_variant_builder_add(setting_builder, "{sv}", secret_name, val);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
static void
|
|
|
|
|
_set_error_secret_property_not_found(GError **error, NMSetting *setting, const char *secret_name)
|
|
|
|
|
{
|
|
|
|
|
g_set_error_literal(error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_PROPERTY_NOT_FOUND,
|
|
|
|
|
_("not a secret property"));
|
|
|
|
|
g_prefix_error(error, "%s.%s: ", nm_setting_get_name(setting), secret_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_setting_property_is_regular_secret(NMSetting *setting, const char *secret_name)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
const NMSettInfoProperty *property;
|
2019-01-06 13:49:46 +01:00
|
|
|
|
|
|
|
|
nm_assert(NM_IS_SETTING(setting));
|
|
|
|
|
nm_assert(secret_name);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
property = _nm_setting_class_get_property_info(NM_SETTING_GET_CLASS(setting), secret_name);
|
2019-01-06 13:49:46 +01:00
|
|
|
return property && property->param_spec
|
|
|
|
|
&& NM_FLAGS_HAS(property->param_spec->flags, NM_SETTING_PARAM_SECRET);
|
|
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
gboolean
|
|
|
|
|
_nm_setting_property_is_regular_secret_flags(NMSetting *setting, const char *secret_flags_name)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoProperty *property;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
nm_assert(NM_IS_SETTING(setting));
|
|
|
|
|
nm_assert(secret_flags_name);
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
property =
|
|
|
|
|
_nm_setting_class_get_property_info(NM_SETTING_GET_CLASS(setting), secret_flags_name);
|
2019-01-06 13:49:46 +01:00
|
|
|
return property && property->param_spec
|
|
|
|
|
&& !NM_FLAGS_HAS(property->param_spec->flags, NM_SETTING_PARAM_SECRET)
|
|
|
|
|
&& G_PARAM_SPEC_VALUE_TYPE(property->param_spec) == NM_TYPE_SETTING_SECRET_FLAGS;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
get_secret_flags(NMSetting * setting,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
NMSettingSecretFlags *out_flags,
|
|
|
|
|
GError ** error)
|
|
|
|
|
{
|
2019-01-06 13:49:46 +01:00
|
|
|
gs_free char * secret_flags_name_free = NULL;
|
|
|
|
|
const char * secret_flags_name;
|
|
|
|
|
NMSettingSecretFlags flags;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
if (!_nm_setting_property_is_regular_secret(setting, secret_name)) {
|
|
|
|
|
_set_error_secret_property_not_found(error, setting, secret_name);
|
2017-11-20 13:52:18 +01:00
|
|
|
NM_SET_OUT(out_flags, NM_SETTING_SECRET_FLAG_NONE);
|
libnm-util: don't assert in nm_setting_get_secret_flags() and avoid assertion in agent_secrets_done_cb()
When secret providers return the connection hash in GetSecrets(),
this hash should only contain secrets. However, some providers also
return non-secret properties.
for_each_secret() iterated over all entries of the @secrets hash
and triggered the assertion in nm_setting_get_secret_flags() (see
below).
NM should not assert against user provided input. Change
nm_setting_get_secret_flags() to silently return FALSE, if the property
is not a secret.
Indeed, handling of secrets is very different for NMSettingVpn and
others. Hence nm_setting_get_secret_flags() has only an inconsistent
behavior and we have to fix all call sites to do the right thing
(depending on whether we have a VPN setting or not).
Now for_each_secret() checks whether the property is a secret
without hitting the assertion. Adjust all other calls of
nm_setting_get_secret_flags(), to anticipate non-secret flags and
assert/warn where appropriate.
Also, agent_secrets_done_cb() clears now all non-secrets properties
from the hash, using the new argument @remove_non_secrets when calling
for_each_secret().
#0 0x0000003370c504e9 in g_logv () from /lib64/libglib-2.0.so.0
#1 0x0000003370c5063f in g_log () from /lib64/libglib-2.0.so.0
#2 0x00007fa4b0c1c156 in get_secret_flags (setting=0x1e3ac60, secret_name=0x1ea9180 "security", verify_secret=1, out_flags=0x7fff7507857c, error=0x0) at nm-setting.c:1091
#3 0x00007fa4b0c1c2b2 in nm_setting_get_secret_flags (setting=0x1e3ac60, secret_name=0x1ea9180 "security", out_flags=0x7fff7507857c, error=0x0) at nm-setting.c:1124
#4 0x0000000000463d03 in for_each_secret (connection=0x1deb2f0, secrets=0x1e9f860, callback=0x464f1b <has_system_owned_secrets>, callback_data=0x7fff7507865c) at settings/nm-settings-connection.c:203
#5 0x000000000046525f in agent_secrets_done_cb (manager=0x1dddf50, call_id=1, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_username=0x1e51710 "thom", agent_has_modify=1, setting_name=0x1e91f90 "802-11-wireless-security",
flags=NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION, secrets=0x1e9f860, error=0x0, user_data=0x1deb2f0, other_data2=0x477d61 <get_secrets_cb>, other_data3=0x1ea92a0) at settings/nm-settings-connection.c:757
#6 0x00000000004dc4fd in get_complete_cb (parent=0x1ea6300, secrets=0x1e9f860, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_username=0x1e51710 "thom", error=0x0, user_data=0x1dddf50) at settings/nm-agent-manager.c:1139
#7 0x00000000004dab54 in req_complete_success (req=0x1ea6300, secrets=0x1e9f860, agent_dbus_owner=0x1ddb9e0 ":1.39", agent_uname=0x1e51710 "thom") at settings/nm-agent-manager.c:502
#8 0x00000000004db86e in get_done_cb (agent=0x1e89530, call_id=0x1, secrets=0x1e9f860, error=0x0, user_data=0x1ea6300) at settings/nm-agent-manager.c:856
#9 0x00000000004de9d0 in get_callback (proxy=0x1e47530, call=0x1, user_data=0x1ea10f0) at settings/nm-secret-agent.c:267
#10 0x000000337380cad2 in complete_pending_call_and_unlock () from /lib64/libdbus-1.so.3
#11 0x000000337380fdc1 in dbus_connection_dispatch () from /lib64/libdbus-1.so.3
#12 0x000000342800ad65 in message_queue_dispatch () from /lib64/libdbus-glib-1.so.2
#13 0x0000003370c492a6 in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#14 0x0000003370c49628 in g_main_context_iterate.isra.24 () from /lib64/libglib-2.0.so.0
#15 0x0000003370c49a3a in g_main_loop_run () from /lib64/libglib-2.0.so.0
#16 0x000000000042e5c6 in main (argc=1, argv=0x7fff75078e88) at main.c:644
Signed-off-by: Thomas Haller <thaller@redhat.com>
2014-02-23 17:03:01 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
secret_flags_name = nm_construct_name_a("%s-flags", secret_name, &secret_flags_name_free);
|
|
|
|
|
|
|
|
|
|
nm_assert(_nm_setting_property_is_regular_secret_flags(setting, secret_flags_name));
|
|
|
|
|
|
2017-11-20 13:52:18 +01:00
|
|
|
g_object_get(G_OBJECT(setting), secret_flags_name, &flags, NULL);
|
|
|
|
|
NM_SET_OUT(out_flags, flags);
|
2014-07-24 08:53:33 -04:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_get_secret_flags:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @secret_name: the secret key name to get flags for
|
|
|
|
|
* @out_flags: on success, the #NMSettingSecretFlags for the secret
|
|
|
|
|
* @error: location to store error, or %NULL
|
|
|
|
|
*
|
|
|
|
|
* For a given secret, retrieves the #NMSettingSecretFlags describing how to
|
|
|
|
|
* handle that secret.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE on success (if the given secret name was a valid property of
|
|
|
|
|
* this setting, and if that property is secret), %FALSE if not
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_get_secret_flags(NMSetting * setting,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
NMSettingSecretFlags *out_flags,
|
|
|
|
|
GError ** error)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), FALSE);
|
|
|
|
|
g_return_val_if_fail(secret_name != NULL, FALSE);
|
|
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
return NM_SETTING_GET_CLASS(setting)->get_secret_flags(setting, secret_name, out_flags, error);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
set_secret_flags(NMSetting * setting,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
NMSettingSecretFlags flags,
|
|
|
|
|
GError ** error)
|
|
|
|
|
{
|
2019-01-06 13:49:46 +01:00
|
|
|
gs_free char *secret_flags_name_free = NULL;
|
|
|
|
|
const char * secret_flags_name;
|
|
|
|
|
|
|
|
|
|
if (!_nm_setting_property_is_regular_secret(setting, secret_name)) {
|
|
|
|
|
_set_error_secret_property_not_found(error, setting, secret_name);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
secret_flags_name = nm_construct_name_a("%s-flags", secret_name, &secret_flags_name_free);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
nm_assert(_nm_setting_property_is_regular_secret_flags(setting, secret_flags_name));
|
|
|
|
|
|
|
|
|
|
if (!nm_g_object_set_property_flags(G_OBJECT(setting),
|
|
|
|
|
secret_flags_name,
|
|
|
|
|
NM_TYPE_SETTING_SECRET_FLAGS,
|
|
|
|
|
flags,
|
|
|
|
|
error))
|
|
|
|
|
g_return_val_if_reached(FALSE);
|
2014-07-24 08:53:33 -04:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_set_secret_flags:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @secret_name: the secret key name to set flags for
|
|
|
|
|
* @flags: the #NMSettingSecretFlags for the secret
|
|
|
|
|
* @error: location to store error, or %NULL
|
|
|
|
|
*
|
|
|
|
|
* For a given secret, stores the #NMSettingSecretFlags describing how to
|
|
|
|
|
* handle that secret.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE on success (if the given secret name was a valid property of
|
|
|
|
|
* this setting, and if that property is secret), %FALSE if not
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_set_secret_flags(NMSetting * setting,
|
|
|
|
|
const char * secret_name,
|
|
|
|
|
NMSettingSecretFlags flags,
|
|
|
|
|
GError ** error)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), FALSE);
|
|
|
|
|
g_return_val_if_fail(secret_name != NULL, FALSE);
|
2018-12-29 21:23:09 +01:00
|
|
|
g_return_val_if_fail(_nm_setting_secret_flags_valid(flags), FALSE);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
return NM_SETTING_GET_CLASS(setting)->set_secret_flags(setting, secret_name, flags, error);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_to_string:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
*
|
2018-07-26 11:59:24 +02:00
|
|
|
* Convert the setting (including secrets!) into a string. For debugging
|
|
|
|
|
* purposes ONLY, should NOT be used for serialization of the setting,
|
|
|
|
|
* or machine-parsed in any way. The output format is not guaranteed to
|
|
|
|
|
* be stable and may change at any time.
|
2014-07-24 08:53:33 -04:00
|
|
|
*
|
|
|
|
|
* Returns: an allocated string containing a textual representation of the
|
2018-07-26 11:59:24 +02:00
|
|
|
* setting's properties and values, which the caller should
|
2014-07-24 08:53:33 -04:00
|
|
|
* free with g_free()
|
|
|
|
|
**/
|
|
|
|
|
char *
|
|
|
|
|
nm_setting_to_string(NMSetting *setting)
|
|
|
|
|
{
|
|
|
|
|
GString * string;
|
2018-07-26 12:34:23 +02:00
|
|
|
gs_unref_variant GVariant *variant = NULL;
|
2018-07-26 11:59:24 +02:00
|
|
|
GVariant * child;
|
|
|
|
|
GVariantIter iter;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
string = g_string_new(nm_setting_get_name(setting));
|
|
|
|
|
g_string_append_c(string, '\n');
|
|
|
|
|
|
2019-06-27 09:07:16 +02:00
|
|
|
variant = _nm_setting_to_dbus(setting, NULL, NM_CONNECTION_SERIALIZE_ALL, NULL);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2018-07-26 11:59:24 +02:00
|
|
|
g_variant_iter_init(&iter, variant);
|
|
|
|
|
while ((child = g_variant_iter_next_value(&iter))) {
|
2018-07-26 12:34:23 +02:00
|
|
|
gs_free char * name = NULL;
|
|
|
|
|
gs_free char * value_str = NULL;
|
|
|
|
|
gs_unref_variant GVariant *value = NULL;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2018-07-26 11:59:24 +02:00
|
|
|
g_variant_get(child, "{sv}", &name, &value);
|
|
|
|
|
value_str = g_variant_print(value, FALSE);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2018-07-26 11:59:24 +02:00
|
|
|
g_string_append_printf(string, "\t%s : %s\n", name, value_str);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_string_free(string, FALSE);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
static GVariant *
|
libnm: use macros function arguments for NMSettInfoPropertType
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.
2021-07-26 23:45:31 +02:00
|
|
|
_nm_setting_get_deprecated_virtual_interface_name(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil)
|
2014-08-04 19:57:20 -04:00
|
|
|
{
|
|
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
|
2018-08-09 14:55:30 +02:00
|
|
|
if (!connection)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2014-08-04 19:57:20 -04:00
|
|
|
s_con = nm_connection_get_setting_connection(connection);
|
2018-08-09 14:55:30 +02:00
|
|
|
if (!s_con)
|
|
|
|
|
return NULL;
|
2014-08-04 19:57:20 -04:00
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
if (nm_setting_connection_get_interface_name(s_con))
|
|
|
|
|
return g_variant_new_string(nm_setting_connection_get_interface_name(s_con));
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
2014-08-04 19:57:20 -04:00
|
|
|
}
|
|
|
|
|
|
2021-06-18 09:59:40 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_interface_name =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_STRING,
|
2021-06-29 17:03:37 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_ignore,
|
2021-06-18 09:59:40 +02:00
|
|
|
.to_dbus_fcn =
|
|
|
|
|
_nm_setting_get_deprecated_virtual_interface_name, );
|
|
|
|
|
|
2021-06-29 22:28:07 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_setting_name =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_STRING,
|
2021-06-30 00:05:49 +02:00
|
|
|
.to_dbus_fcn = _nm_setting_property_to_dbus_fcn_ignore,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_ignore,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
2021-06-29 22:28:07 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_ignore);
|
|
|
|
|
|
2021-06-18 09:59:40 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_ignore_i =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(
|
|
|
|
|
G_VARIANT_TYPE_INT32,
|
|
|
|
|
/* No functions set. This property type is to silently ignore the value on D-Bus. */
|
2021-06-29 17:03:37 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_ignore);
|
2021-06-18 09:59:40 +02:00
|
|
|
|
|
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_ignore_u =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(
|
|
|
|
|
G_VARIANT_TYPE_UINT32,
|
|
|
|
|
/* No functions set. This property type is to silently ignore the value on D-Bus. */
|
2021-06-29 17:03:37 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_ignore);
|
2021-06-18 09:59:40 +02:00
|
|
|
|
|
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_plain_i =
|
2021-06-29 14:23:16 +02:00
|
|
|
NM_SETT_INFO_PROPERT_TYPE_GPROP_INIT(G_VARIANT_TYPE_INT32,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
2021-06-18 09:59:40 +02:00
|
|
|
|
|
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_plain_u =
|
2021-06-29 14:23:16 +02:00
|
|
|
NM_SETT_INFO_PROPERT_TYPE_GPROP_INIT(G_VARIANT_TYPE_UINT32,
|
2021-06-30 00:05:49 +02:00
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_default,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_gprop,
|
|
|
|
|
.from_dbus_is_full = TRUE);
|
2019-09-22 10:57:57 +02:00
|
|
|
|
2021-06-28 17:04:37 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_direct_boolean =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_BOOLEAN,
|
2021-06-30 00:05:49 +02:00
|
|
|
.direct_type = NM_VALUE_TYPE_BOOL,
|
|
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_direct,
|
|
|
|
|
.to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct,
|
2021-07-14 15:48:37 +02:00
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
|
|
|
|
.from_dbus_direct_allow_transform = TRUE);
|
2021-06-28 17:04:37 +02:00
|
|
|
|
2021-07-13 22:56:05 +02:00
|
|
|
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,
|
2021-07-14 15:48:37 +02:00
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
|
|
|
|
.from_dbus_direct_allow_transform = TRUE);
|
2021-07-13 22:56:05 +02:00
|
|
|
|
2021-06-29 07:57:41 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_direct_uint32 =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_UINT32,
|
2021-06-30 00:05:49 +02:00
|
|
|
.direct_type = NM_VALUE_TYPE_UINT32,
|
|
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_direct,
|
|
|
|
|
.to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct,
|
2021-07-14 15:48:37 +02:00
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
|
|
|
|
.from_dbus_direct_allow_transform = TRUE);
|
2021-06-29 07:57:41 +02:00
|
|
|
|
2021-10-20 10:53:39 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_direct_uint64 =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_UINT64,
|
|
|
|
|
.direct_type = NM_VALUE_TYPE_UINT64,
|
|
|
|
|
.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_direct,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
|
|
|
|
.from_dbus_direct_allow_transform = TRUE);
|
|
|
|
|
|
2021-06-28 19:17:19 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_direct_string =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_STRING,
|
2021-06-30 00:05:49 +02:00
|
|
|
.direct_type = NM_VALUE_TYPE_STRING,
|
|
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_direct,
|
2021-10-20 10:53:39 +02:00
|
|
|
.to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
|
|
|
|
.from_dbus_direct_allow_transform = TRUE);
|
|
|
|
|
|
2021-10-27 20:24:17 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_direct_bytes =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_BYTESTRING,
|
|
|
|
|
.direct_type = NM_VALUE_TYPE_BYTES,
|
|
|
|
|
.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_direct,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
|
|
|
|
.from_dbus_direct_allow_transform = TRUE);
|
|
|
|
|
|
2021-10-20 10:53:39 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_direct_enum =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_INT32,
|
|
|
|
|
.direct_type = NM_VALUE_TYPE_ENUM,
|
|
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_direct,
|
2021-06-30 00:05:49 +02:00
|
|
|
.to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct,
|
2021-07-14 15:48:37 +02:00
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
|
|
|
|
.from_dbus_direct_allow_transform = TRUE);
|
2021-10-20 10:53:39 +02:00
|
|
|
|
|
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_direct_flags =
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(G_VARIANT_TYPE_UINT32,
|
|
|
|
|
.direct_type = NM_VALUE_TYPE_FLAGS,
|
|
|
|
|
.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_direct,
|
|
|
|
|
.from_dbus_is_full = TRUE,
|
|
|
|
|
.from_dbus_direct_allow_transform = TRUE);
|
2021-06-28 19:17:19 +02:00
|
|
|
|
2021-07-13 18:09:13 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_direct_mac_address =
|
2021-07-14 15:31:43 +02:00
|
|
|
NM_SETT_INFO_PROPERT_TYPE_DBUS_INIT(
|
|
|
|
|
G_VARIANT_TYPE_BYTESTRING,
|
|
|
|
|
.direct_type = NM_VALUE_TYPE_STRING,
|
|
|
|
|
.compare_fcn = _nm_setting_property_compare_fcn_direct,
|
|
|
|
|
.to_dbus_fcn = _nm_setting_property_to_dbus_fcn_direct_mac_address,
|
|
|
|
|
.from_dbus_fcn = _nm_setting_property_from_dbus_fcn_direct_mac_address);
|
2021-07-13 18:09:13 +02:00
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
static GenData *
|
|
|
|
|
_gendata_hash(NMSetting *setting, gboolean create_if_necessary)
|
|
|
|
|
{
|
|
|
|
|
NMSettingPrivate *priv;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_SETTING(setting));
|
|
|
|
|
|
|
|
|
|
priv = NM_SETTING_GET_PRIVATE(setting);
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY(!priv->gendata)) {
|
|
|
|
|
if (!create_if_necessary)
|
|
|
|
|
return NULL;
|
|
|
|
|
priv->gendata = g_slice_new(GenData);
|
|
|
|
|
priv->gendata->hash = g_hash_table_new_full(nm_str_hash,
|
|
|
|
|
g_str_equal,
|
|
|
|
|
g_free,
|
|
|
|
|
(GDestroyNotify) g_variant_unref);
|
|
|
|
|
priv->gendata->names = NULL;
|
|
|
|
|
priv->gendata->values = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return priv->gendata;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GHashTable *
|
2020-05-14 09:16:32 +02:00
|
|
|
_nm_setting_option_hash(NMSetting *setting, gboolean create_if_necessary)
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
{
|
|
|
|
|
GenData *gendata;
|
|
|
|
|
|
|
|
|
|
gendata = _gendata_hash(setting, create_if_necessary);
|
|
|
|
|
return gendata ? gendata->hash : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2020-05-14 09:16:32 +02:00
|
|
|
_nm_setting_option_notify(NMSetting *setting, gboolean names_changed)
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
{
|
|
|
|
|
GenData *gendata;
|
|
|
|
|
|
|
|
|
|
gendata = _gendata_hash(setting, FALSE);
|
|
|
|
|
if (!gendata)
|
2019-01-20 14:01:24 +01:00
|
|
|
goto out;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
nm_clear_g_free(&gendata->values);
|
|
|
|
|
|
|
|
|
|
if (names_changed) {
|
|
|
|
|
/* if only the values changed, it's sufficient to invalidate the
|
|
|
|
|
* values cache. Otherwise, the names cache must be invalidated too. */
|
|
|
|
|
nm_clear_g_free(&gendata->names);
|
|
|
|
|
}
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
|
2019-01-20 14:01:24 +01:00
|
|
|
/* Note, currently there is no way to notify the subclass when gendata changed.
|
libnm, cli, ifcfg-rh: add NMSettingEthtool setting
Note that in NetworkManager API (D-Bus, libnm, and nmcli),
the features are called "feature-xyz". The "feature-" prefix
is used, because NMSettingEthtool possibly will gain support
for options that are not only -K|--offload|--features, for
example -C|--coalesce.
The "xzy" suffix is either how ethtool utility calls the feature
("tso", "rx"). Or, if ethtool utility specifies no alias for that
feature, it's the name from kernel's ETH_SS_FEATURES ("tx-tcp6-segmentation").
If possible, we prefer ethtool utility's naming.
Also note, how the features "feature-sg", "feature-tso", and
"feature-tx" actually refer to multiple underlying kernel features
at once. This too follows what ethtool utility does.
The functionality is not yet implemented server-side.
2018-07-16 23:37:55 +02:00
|
|
|
* gendata is only changed in two situations:
|
|
|
|
|
* 1) from within NMSetting itself, for example when creating a NMSetting instance
|
|
|
|
|
* from keyfile or a D-Bus GVariant.
|
|
|
|
|
* 2) actively from the subclass itself
|
|
|
|
|
* For 2), we don't need the notification, because the subclass knows that something
|
|
|
|
|
* changed.
|
|
|
|
|
* For 1), we currently don't need the notification either, because all that the subclass
|
|
|
|
|
* currently would do, is emit a g_object_notify() signal. However, 1) only happens when
|
|
|
|
|
* the setting instance is newly created, at that point, nobody listens to the signal.
|
|
|
|
|
*
|
|
|
|
|
* If we ever need it, then we would need to call a virtual function to notify the subclass
|
|
|
|
|
* that gendata changed. */
|
2019-01-20 14:01:24 +01:00
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
_nm_setting_emit_property_changed(setting);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guint
|
2020-05-14 09:16:32 +02:00
|
|
|
_nm_setting_option_get_all(NMSetting * setting,
|
|
|
|
|
const char *const **out_names,
|
|
|
|
|
GVariant *const ** out_values)
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
{
|
|
|
|
|
GenData * gendata;
|
|
|
|
|
GHashTable *hash;
|
|
|
|
|
guint i, len;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
nm_assert(NM_IS_SETTING(setting));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
gendata = _gendata_hash(setting, FALSE);
|
|
|
|
|
if (!gendata)
|
|
|
|
|
goto out_zero;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
hash = gendata->hash;
|
|
|
|
|
len = g_hash_table_size(hash);
|
|
|
|
|
if (len == 0)
|
|
|
|
|
goto out_zero;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (!out_names && !out_values)
|
|
|
|
|
return len;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (G_UNLIKELY(!gendata->names)) {
|
2021-07-30 09:15:38 +02:00
|
|
|
gendata->names = nm_strdict_get_keys(hash, TRUE, NULL);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (out_values) {
|
|
|
|
|
if (G_UNLIKELY(!gendata->values)) {
|
|
|
|
|
gendata->values = g_new(GVariant *, len + 1);
|
|
|
|
|
for (i = 0; i < len; i++)
|
|
|
|
|
gendata->values[i] = g_hash_table_lookup(hash, gendata->names[i]);
|
|
|
|
|
gendata->values[i] = NULL;
|
|
|
|
|
}
|
|
|
|
|
*out_values = gendata->values;
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
NM_SET_OUT(out_names, (const char *const *) gendata->names);
|
|
|
|
|
return len;
|
|
|
|
|
|
|
|
|
|
out_zero:
|
|
|
|
|
NM_SET_OUT(out_names, NULL);
|
|
|
|
|
NM_SET_OUT(out_values, NULL);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2020-05-14 09:16:33 +02:00
|
|
|
* nm_setting_option_get_all_names:
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
* @setting: the #NMSetting
|
2019-03-06 20:04:50 +01:00
|
|
|
* @out_len: (allow-none) (out):
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
*
|
2020-05-14 09:16:33 +02:00
|
|
|
* Gives the name of all set options.
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
*
|
|
|
|
|
* Returns: (array length=out_len zero-terminated=1) (transfer none):
|
|
|
|
|
* A %NULL terminated array of key names. If no names are present, this returns
|
|
|
|
|
* %NULL. The returned array and the names are owned by %NMSetting and might be invalidated
|
2020-05-14 09:16:33 +02:00
|
|
|
* by the next operation.
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
*
|
2020-05-14 09:16:33 +02:00
|
|
|
* Since: 1.26
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
**/
|
|
|
|
|
const char *const *
|
2020-05-14 09:16:33 +02:00
|
|
|
nm_setting_option_get_all_names(NMSetting *setting, guint *out_len)
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
{
|
|
|
|
|
const char *const *names;
|
|
|
|
|
guint len;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), NULL);
|
|
|
|
|
|
2020-05-14 09:16:32 +02:00
|
|
|
len = _nm_setting_option_get_all(setting, &names, NULL);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
NM_SET_OUT(out_len, len);
|
|
|
|
|
return names;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 15:26:30 +02:00
|
|
|
gboolean
|
2020-05-14 09:16:32 +02:00
|
|
|
_nm_setting_option_clear(NMSetting *setting, const char *optname)
|
2020-05-15 15:26:30 +02:00
|
|
|
{
|
|
|
|
|
GHashTable *ht;
|
|
|
|
|
|
|
|
|
|
nm_assert(NM_IS_SETTING(setting));
|
|
|
|
|
nm_assert(nm_str_not_empty(optname));
|
|
|
|
|
|
2020-05-14 09:16:32 +02:00
|
|
|
ht = _nm_setting_option_hash(setting, FALSE);
|
2020-05-15 15:26:30 +02:00
|
|
|
if (!ht)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return g_hash_table_remove(ht, optname);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 09:16:33 +02:00
|
|
|
/**
|
|
|
|
|
* nm_setting_option_clear_by_name:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @predicate: (allow-none) (scope call): the predicate for which names
|
|
|
|
|
* should be clear.
|
|
|
|
|
* If the predicate returns %TRUE for an option name, the option
|
|
|
|
|
* gets removed. If %NULL, all options will be removed.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.26
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_option_clear_by_name(NMSetting *setting, NMUtilsPredicateStr predicate)
|
2020-05-15 15:26:30 +02:00
|
|
|
{
|
2020-05-14 09:16:33 +02:00
|
|
|
GHashTable * hash;
|
2020-05-15 15:26:30 +02:00
|
|
|
GHashTableIter iter;
|
2020-05-14 09:16:33 +02:00
|
|
|
const char * name;
|
2020-05-15 15:26:30 +02:00
|
|
|
gboolean changed = FALSE;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:33 +02:00
|
|
|
g_return_if_fail(NM_IS_SETTING(setting));
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:33 +02:00
|
|
|
hash = _nm_setting_option_hash(NM_SETTING(setting), FALSE);
|
|
|
|
|
if (!hash)
|
|
|
|
|
return;
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:33 +02:00
|
|
|
if (!predicate) {
|
|
|
|
|
changed = (g_hash_table_size(hash) > 0);
|
|
|
|
|
if (changed)
|
|
|
|
|
g_hash_table_remove_all(hash);
|
|
|
|
|
} else {
|
|
|
|
|
g_hash_table_iter_init(&iter, hash);
|
|
|
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &name, NULL)) {
|
|
|
|
|
if (predicate(name)) {
|
|
|
|
|
g_hash_table_iter_remove(&iter);
|
|
|
|
|
changed = TRUE;
|
|
|
|
|
}
|
2020-05-15 15:26:30 +02:00
|
|
|
}
|
|
|
|
|
}
|
2020-09-28 16:03:33 +02:00
|
|
|
|
2020-05-14 09:16:33 +02:00
|
|
|
if (changed)
|
|
|
|
|
_nm_setting_option_notify(setting, TRUE);
|
2020-05-15 15:26:30 +02:00
|
|
|
}
|
|
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
libnm: add API for setting gendata options to NMSetting (nm_setting_option_get())
NMSettingEthtool is implemented using "gendata", meaning a hash
of GVariant. This is different from most other settings that have
properties implemented as GObject properties. There are two reasons
for this approach:
- The setting is transferred via D-Bus as "a{sv}" dictionary.
By unpacking the dictionary into GObject properties, the setting
cannot handle unknown properties. To be forward compatible (and
due to sloppy programming), unknown dictionary keys are silently
ignored when parsing a NMSetting. That is error prone and also
prevents settings to be treated loss-less.
Instead, we should at first accept all values from the dictionary.
Only in a second step, nm_connection_verify() rejects invalid settings
with an error reason. This way, the user can create a NMSetting,
but in a separate step handle if the setting doesn't verify.
"gendata" solves this by tracking the full GVariant dictionary.
This is still not entirely lossless, because multiple keys are
combined.
This is for example interesting if an libnm client fetches a connection
from a newer NetworkManager version. Now the user can modify the
properties that she knows about, while leaving all unknown
properties (from newer versions) in place.
- the approach aims to reduce the necessary boiler plate to create
GObject properties. Adding a new property should require less new code.
This approach was always be intended to be suitable for all settings, not only
NMSettingEthtool. We should not once again try to add API like
nm_setting_ethtool_set_feature(), nm_setting_ethtool_set_coalesce(), etc.
Note that the option name already fully encodes whether it is a feature,
a coalesce option, or whatever. We should not have
"nm_setting_set_$SUB_GROUP (setting, $ONE_NAME_FROM_GROUP)" API, but
simply "nm_setting_option_set (setting, $OPTION)" accessors.
Also, when parsing a NMSettingEthtool from a GVariant, then a feature
option can be any kind of variant. Only nm_setting_verify() rejects
variants of the wrong type. As such, nm_setting_option_set*() also
doesn't validate whether the variant type matches the option. Of course,
if you set a value of wrong type, verify() will reject the setting.
Add new general purpose API for this and expose it for NMSetting.
2020-05-14 09:16:32 +02:00
|
|
|
/**
|
|
|
|
|
* nm_setting_option_get:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @opt_name: the option name to request.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): the #GVariant or %NULL if the option
|
|
|
|
|
* is not set.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.26.
|
|
|
|
|
*/
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_setting_option_get(NMSetting *setting, const char *opt_name)
|
|
|
|
|
{
|
|
|
|
|
GenData *gendata;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail(NM_IS_SETTING(setting), FALSE);
|
|
|
|
|
g_return_val_if_fail(opt_name, FALSE);
|
|
|
|
|
|
|
|
|
|
gendata = _gendata_hash(setting, FALSE);
|
|
|
|
|
return gendata ? g_hash_table_lookup(gendata->hash, opt_name) : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 09:16:32 +02:00
|
|
|
/**
|
|
|
|
|
* nm_setting_option_get_boolean:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @opt_name: the option to get
|
|
|
|
|
* @out_value: (allow-none) (out): the optional output value.
|
|
|
|
|
* If the option is unset, %FALSE will be returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if @opt_name is set to a boolean variant.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.26
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_option_get_boolean(NMSetting *setting, const char *opt_name, gboolean *out_value)
|
|
|
|
|
{
|
|
|
|
|
GVariant *v;
|
|
|
|
|
|
|
|
|
|
v = nm_setting_option_get(NM_SETTING(setting), opt_name);
|
|
|
|
|
if (v && g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN)) {
|
|
|
|
|
NM_SET_OUT(out_value, g_variant_get_boolean(v));
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
NM_SET_OUT(out_value, FALSE);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-20 16:31:30 +02:00
|
|
|
/**
|
|
|
|
|
* nm_setting_option_get_uint32:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @opt_name: the option to get
|
|
|
|
|
* @out_value: (allow-none) (out): the optional output value.
|
|
|
|
|
* If the option is unset, 0 will be returned.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if @opt_name is set to a uint32 variant.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.26
|
|
|
|
|
*/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_option_get_uint32(NMSetting *setting, const char *opt_name, guint32 *out_value)
|
|
|
|
|
{
|
|
|
|
|
GVariant *v;
|
|
|
|
|
|
|
|
|
|
v = nm_setting_option_get(NM_SETTING(setting), opt_name);
|
|
|
|
|
if (v && g_variant_is_of_type(v, G_VARIANT_TYPE_UINT32)) {
|
|
|
|
|
NM_SET_OUT(out_value, g_variant_get_uint32(v));
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
NM_SET_OUT(out_value, 0);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-14 09:16:32 +02:00
|
|
|
/**
|
|
|
|
|
* nm_setting_option_set:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @opt_name: the option name to set
|
|
|
|
|
* @variant: (allow-none): the variant to set.
|
|
|
|
|
*
|
|
|
|
|
* If @variant is %NULL, this clears the option if it is set.
|
|
|
|
|
* Otherwise, @variant is set as the option. If @variant is
|
|
|
|
|
* a floating reference, it will be consumed.
|
|
|
|
|
*
|
|
|
|
|
* Note that not all setting types support options. It is a bug
|
|
|
|
|
* setting a variant to a setting that doesn't support it.
|
2020-07-01 17:20:40 -04:00
|
|
|
* Currently, only #NMSettingEthtool supports it.
|
2020-05-14 09:16:32 +02:00
|
|
|
*
|
|
|
|
|
* Since: 1.26
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_option_set(NMSetting *setting, const char *opt_name, GVariant *variant)
|
|
|
|
|
{
|
|
|
|
|
GVariant * old_variant;
|
|
|
|
|
gboolean changed_name;
|
|
|
|
|
gboolean changed_value;
|
|
|
|
|
GHashTable *hash;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(NM_IS_SETTING(setting));
|
|
|
|
|
g_return_if_fail(opt_name);
|
|
|
|
|
|
|
|
|
|
hash = _nm_setting_option_hash(setting, variant != NULL);
|
|
|
|
|
|
|
|
|
|
if (!variant) {
|
|
|
|
|
if (hash) {
|
|
|
|
|
if (g_hash_table_remove(hash, opt_name))
|
|
|
|
|
_nm_setting_option_notify(setting, TRUE);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Currently, it is a bug setting any option, unless the setting type supports it.
|
|
|
|
|
* And currently, only NMSettingEthtool supports it.
|
|
|
|
|
*
|
|
|
|
|
* In the future, more setting types may support it. Or we may relax this so
|
|
|
|
|
* that options can be attached to all setting types (to indicate "unsupported"
|
|
|
|
|
* settings for forward compatibility).
|
|
|
|
|
*
|
|
|
|
|
* As it is today, internal code will only add gendata options to NMSettingEthtool,
|
|
|
|
|
* and there exists not public API to add such options. Still, it is permissible
|
|
|
|
|
* to call get(), clear() and set(variant=NULL) also on settings that don't support
|
|
|
|
|
* it, as these operations don't add options.
|
|
|
|
|
*/
|
|
|
|
|
g_return_if_fail(
|
|
|
|
|
_nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting))->detail.gendata_info);
|
|
|
|
|
|
|
|
|
|
old_variant = g_hash_table_lookup(hash, opt_name);
|
|
|
|
|
|
|
|
|
|
changed_name = (old_variant == NULL);
|
|
|
|
|
changed_value = changed_name || !g_variant_equal(old_variant, variant);
|
|
|
|
|
|
|
|
|
|
/* We always want to replace the variant, even if it has
|
|
|
|
|
* the same value according to g_variant_equal(). The reason
|
|
|
|
|
* is that we want to take a reference on @variant, because
|
|
|
|
|
* that is what the user might expect. */
|
|
|
|
|
g_hash_table_insert(hash, g_strdup(opt_name), g_variant_ref_sink(variant));
|
|
|
|
|
|
|
|
|
|
if (changed_value)
|
|
|
|
|
_nm_setting_option_notify(setting, !changed_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_option_set_boolean:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @value: the value to set.
|
|
|
|
|
*
|
|
|
|
|
* Like nm_setting_option_set() to set a boolean GVariant.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.26
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_option_set_boolean(NMSetting *setting, const char *opt_name, gboolean value)
|
|
|
|
|
{
|
|
|
|
|
GVariant * old_variant;
|
|
|
|
|
gboolean changed_name;
|
|
|
|
|
gboolean changed_value;
|
|
|
|
|
GHashTable *hash;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(NM_IS_SETTING(setting));
|
|
|
|
|
g_return_if_fail(opt_name);
|
|
|
|
|
|
|
|
|
|
value = (!!value);
|
|
|
|
|
|
|
|
|
|
hash = _nm_setting_option_hash(setting, TRUE);
|
|
|
|
|
|
|
|
|
|
old_variant = g_hash_table_lookup(hash, opt_name);
|
|
|
|
|
|
|
|
|
|
changed_name = (old_variant == NULL);
|
|
|
|
|
changed_value = changed_name
|
|
|
|
|
|| (!g_variant_is_of_type(old_variant, G_VARIANT_TYPE_BOOLEAN)
|
|
|
|
|
|| g_variant_get_boolean(old_variant) != value);
|
|
|
|
|
|
|
|
|
|
g_hash_table_insert(hash, g_strdup(opt_name), g_variant_ref_sink(g_variant_new_boolean(value)));
|
|
|
|
|
|
|
|
|
|
if (changed_value)
|
|
|
|
|
_nm_setting_option_notify(setting, !changed_name);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-20 16:31:30 +02:00
|
|
|
/**
|
|
|
|
|
* nm_setting_option_set_uint32:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
* @value: the value to set.
|
|
|
|
|
*
|
|
|
|
|
* Like nm_setting_option_set() to set a uint32 GVariant.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.26
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_option_set_uint32(NMSetting *setting, const char *opt_name, guint32 value)
|
|
|
|
|
{
|
|
|
|
|
GVariant * old_variant;
|
|
|
|
|
gboolean changed_name;
|
|
|
|
|
gboolean changed_value;
|
|
|
|
|
GHashTable *hash;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail(NM_IS_SETTING(setting));
|
|
|
|
|
g_return_if_fail(opt_name);
|
|
|
|
|
|
|
|
|
|
hash = _nm_setting_option_hash(setting, TRUE);
|
|
|
|
|
|
|
|
|
|
old_variant = g_hash_table_lookup(hash, opt_name);
|
|
|
|
|
|
|
|
|
|
changed_name = (old_variant == NULL);
|
|
|
|
|
changed_value = changed_name
|
|
|
|
|
|| (!g_variant_is_of_type(old_variant, G_VARIANT_TYPE_UINT32)
|
|
|
|
|
|| g_variant_get_uint32(old_variant) != value);
|
|
|
|
|
|
|
|
|
|
g_hash_table_insert(hash, g_strdup(opt_name), g_variant_ref_sink(g_variant_new_uint32(value)));
|
|
|
|
|
|
|
|
|
|
if (changed_value)
|
|
|
|
|
_nm_setting_option_notify(setting, !changed_name);
|
|
|
|
|
}
|
|
|
|
|
|
libnm: add API for setting gendata options to NMSetting (nm_setting_option_get())
NMSettingEthtool is implemented using "gendata", meaning a hash
of GVariant. This is different from most other settings that have
properties implemented as GObject properties. There are two reasons
for this approach:
- The setting is transferred via D-Bus as "a{sv}" dictionary.
By unpacking the dictionary into GObject properties, the setting
cannot handle unknown properties. To be forward compatible (and
due to sloppy programming), unknown dictionary keys are silently
ignored when parsing a NMSetting. That is error prone and also
prevents settings to be treated loss-less.
Instead, we should at first accept all values from the dictionary.
Only in a second step, nm_connection_verify() rejects invalid settings
with an error reason. This way, the user can create a NMSetting,
but in a separate step handle if the setting doesn't verify.
"gendata" solves this by tracking the full GVariant dictionary.
This is still not entirely lossless, because multiple keys are
combined.
This is for example interesting if an libnm client fetches a connection
from a newer NetworkManager version. Now the user can modify the
properties that she knows about, while leaving all unknown
properties (from newer versions) in place.
- the approach aims to reduce the necessary boiler plate to create
GObject properties. Adding a new property should require less new code.
This approach was always be intended to be suitable for all settings, not only
NMSettingEthtool. We should not once again try to add API like
nm_setting_ethtool_set_feature(), nm_setting_ethtool_set_coalesce(), etc.
Note that the option name already fully encodes whether it is a feature,
a coalesce option, or whatever. We should not have
"nm_setting_set_$SUB_GROUP (setting, $ONE_NAME_FROM_GROUP)" API, but
simply "nm_setting_option_set (setting, $OPTION)" accessors.
Also, when parsing a NMSettingEthtool from a GVariant, then a feature
option can be any kind of variant. Only nm_setting_verify() rejects
variants of the wrong type. As such, nm_setting_option_set*() also
doesn't validate whether the variant type matches the option. Of course,
if you set a value of wrong type, verify() will reject the setting.
Add new general purpose API for this and expose it for NMSetting.
2020-05-14 09:16:32 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
static void
|
|
|
|
|
get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
NMSetting *setting = NM_SETTING(object);
|
|
|
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
|
case PROP_NAME:
|
|
|
|
|
g_value_set_string(value, nm_setting_get_name(setting));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-11 08:32:54 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_setting_init(NMSetting *setting)
|
|
|
|
|
{}
|
|
|
|
|
|
2021-06-29 08:52:02 +02:00
|
|
|
static void
|
|
|
|
|
constructed(GObject *object)
|
|
|
|
|
{
|
|
|
|
|
NMSetting * self = NM_SETTING(object);
|
|
|
|
|
NMSettingClass *klass = NM_SETTING_GET_CLASS(self);
|
|
|
|
|
|
|
|
|
|
/* we don't support that NMSetting subclasses override constructed.
|
|
|
|
|
* They all must have no G_PARAM_CONSTRUCT/G_PARAM_CONSTRUCT_ONLY
|
|
|
|
|
* properties, otherwise the automatism of _init_direct() needs
|
|
|
|
|
* careful adjustment. */
|
|
|
|
|
nm_assert(G_OBJECT_CLASS(klass)->constructed == constructed);
|
|
|
|
|
|
|
|
|
|
/* we always initialize the defaults of the (direct) properties. Note that:
|
|
|
|
|
*
|
|
|
|
|
* - we don't use CONSTRUCT properties, because they have an overhead during
|
|
|
|
|
* each object creation. Via _init_direct() we can do it more efficiently.
|
|
|
|
|
*
|
|
|
|
|
* - we always call this, because we want to get all default values right.
|
|
|
|
|
* We even call this for NMSetting subclasses that (historically) are not
|
|
|
|
|
* yet aware of this happening.
|
|
|
|
|
*/
|
|
|
|
|
_init_direct(self);
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(nm_setting_parent_class)->constructed(object);
|
|
|
|
|
}
|
|
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
static void
|
|
|
|
|
finalize(GObject *object)
|
|
|
|
|
{
|
2021-10-23 20:58:27 +02:00
|
|
|
NMSetting * self = NM_SETTING(object);
|
|
|
|
|
NMSettingPrivate *priv = NM_SETTING_GET_PRIVATE(self);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
if (priv->gendata) {
|
|
|
|
|
g_free(priv->gendata->names);
|
|
|
|
|
g_free(priv->gendata->values);
|
|
|
|
|
g_hash_table_unref(priv->gendata->hash);
|
|
|
|
|
g_slice_free(GenData, priv->gendata);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS(nm_setting_parent_class)->finalize(object);
|
2021-06-28 23:51:42 +02:00
|
|
|
|
2021-10-23 20:58:27 +02:00
|
|
|
_finalize_direct(self);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
|
|
|
|
|
2014-07-24 08:53:33 -04:00
|
|
|
static void
|
|
|
|
|
nm_setting_class_init(NMSettingClass *setting_class)
|
|
|
|
|
{
|
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS(setting_class);
|
|
|
|
|
|
|
|
|
|
g_type_class_add_private(setting_class, sizeof(NMSettingPrivate));
|
|
|
|
|
|
2021-06-29 08:52:02 +02:00
|
|
|
object_class->constructed = constructed;
|
2014-07-24 08:53:33 -04:00
|
|
|
object_class->get_property = get_property;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
object_class->finalize = finalize;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-01-11 15:16:33 +01:00
|
|
|
setting_class->update_one_secret = update_one_secret;
|
|
|
|
|
setting_class->get_secret_flags = get_secret_flags;
|
|
|
|
|
setting_class->set_secret_flags = set_secret_flags;
|
2019-01-13 21:23:02 +01:00
|
|
|
setting_class->clear_secrets = clear_secrets;
|
2019-01-31 09:38:58 +01:00
|
|
|
setting_class->for_each_secret = for_each_secret;
|
2019-01-11 15:16:33 +01:00
|
|
|
setting_class->duplicate_copy_properties = duplicate_copy_properties;
|
2019-01-21 08:10:14 +01:00
|
|
|
setting_class->enumerate_values = enumerate_values;
|
2019-01-21 08:46:41 +01:00
|
|
|
setting_class->aggregate = aggregate;
|
2019-05-13 12:22:40 +02:00
|
|
|
setting_class->init_from_dbus = init_from_dbus;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* NMSetting:name:
|
|
|
|
|
*
|
|
|
|
|
* The setting's name, which uniquely identifies the setting within the
|
|
|
|
|
* connection. Each setting type has a name unique to that type, for
|
2018-08-03 13:38:01 +02:00
|
|
|
* example "ppp" or "802-11-wireless" or "802-3-ethernet".
|
2014-07-24 08:53:33 -04:00
|
|
|
**/
|
2019-01-11 08:28:26 +01:00
|
|
|
obj_properties[PROP_NAME] = g_param_spec_string(NM_SETTING_NAME,
|
|
|
|
|
"",
|
|
|
|
|
"",
|
|
|
|
|
NULL,
|
|
|
|
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
|
|
|
|
|
|
|
|
|
|
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|