2019-09-10 11:19:01 +02:00
|
|
|
// SPDX-License-Identifier: LGPL-2.1+
|
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
|
|
|
*/
|
|
|
|
|
|
2015-07-17 14:38:54 +02:00
|
|
|
#include "nm-default.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"
|
2014-02-25 20:30:27 +01:00
|
|
|
#include "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,
|
2014-07-24 08:53:33 -04:00
|
|
|
PROP_NAME,
|
2019-01-11 08:28:26 +01:00
|
|
|
);
|
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);
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2017-06-01 13:43:52 +02:00
|
|
|
static NMSettingPriority
|
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
|
|
|
_get_base_type_priority (const NMMetaSettingInfo *setting_info,
|
|
|
|
|
GType gtype)
|
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
|
|
|
/* Historical oddity: PPPoE is a base-type even though it's not
|
|
|
|
|
* priority 1. It needs to be sorted *after* lower-level stuff like
|
|
|
|
|
* Wi-Fi security or 802.1x for secrets, but it's still allowed as a
|
|
|
|
|
* base type.
|
|
|
|
|
*/
|
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
|
|
|
if (setting_info) {
|
|
|
|
|
if ( NM_IN_SET (setting_info->setting_priority,
|
|
|
|
|
NM_SETTING_PRIORITY_HW_BASE,
|
|
|
|
|
NM_SETTING_PRIORITY_HW_NON_BASE)
|
|
|
|
|
|| gtype == NM_TYPE_SETTING_PPPOE)
|
|
|
|
|
return setting_info->setting_priority;
|
|
|
|
|
}
|
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
|
|
|
return NM_SETTING_PRIORITY_INVALID;
|
2014-07-24 08:53:33 -04: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_type_get_base_type_priority (GType type)
|
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
|
|
|
return _get_base_type_priority (nm_meta_setting_infos_by_gtype (type),
|
|
|
|
|
type);
|
2014-07-24 08:53:33 -04: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);
|
|
|
|
|
|
|
|
|
|
return _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;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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-04-24 15:51:04 +02:00
|
|
|
static GVariant *
|
2019-04-24 16:28:11 +02:00
|
|
|
_gprop_to_dbus_fcn_bytes (const GValue *val)
|
2019-04-24 15:51:04 +02:00
|
|
|
{
|
|
|
|
|
nm_assert (G_VALUE_HOLDS (val, G_TYPE_BYTES));
|
|
|
|
|
return nm_utils_gbytes_to_variant_ay (g_value_get_boxed (val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GVariant *
|
2019-04-24 16:28:11 +02:00
|
|
|
_gprop_to_dbus_fcn_enum (const GValue *val)
|
2019-04-24 15:51:04 +02:00
|
|
|
{
|
|
|
|
|
return g_variant_new_int32 (g_value_get_enum (val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GVariant *
|
2019-04-24 16:28:11 +02:00
|
|
|
_gprop_to_dbus_fcn_flags (const GValue *val)
|
2019-04-24 15:51:04 +02:00
|
|
|
{
|
|
|
|
|
return g_variant_new_uint32 (g_value_get_flags (val));
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
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));
|
|
|
|
|
|
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
|
|
|
#define _PROPERT_EXTRA(prop_info, member) \
|
|
|
|
|
({ \
|
|
|
|
|
const NMSettInfoProperty *_prop_info = (prop_info); \
|
|
|
|
|
\
|
|
|
|
|
(_prop_info->property_type ? _prop_info->property_type->member : 0); \
|
|
|
|
|
})
|
2019-04-24 16:28:11 +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
|
|
|
nm_assert (!_PROPERT_EXTRA (prop_info, gprop_from_dbus_fcn) || _PROPERT_EXTRA (prop_info, dbus_type));
|
|
|
|
|
nm_assert (!_PROPERT_EXTRA (prop_info, from_dbus_fcn) || _PROPERT_EXTRA (prop_info, dbus_type));
|
|
|
|
|
nm_assert (!_PROPERT_EXTRA (prop_info, to_dbus_fcn) || _PROPERT_EXTRA (prop_info, dbus_type));
|
2019-04-24 16:28:11 +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
|
|
|
nm_assert (!_PROPERT_EXTRA (prop_info, to_dbus_fcn) || !_PROPERT_EXTRA (prop_info, gprop_to_dbus_fcn));
|
|
|
|
|
nm_assert (!_PROPERT_EXTRA (prop_info, from_dbus_fcn) || !_PROPERT_EXTRA (prop_info, gprop_from_dbus_fcn));
|
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
|
|
|
|
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 (!_PROPERT_EXTRA (prop_info, gprop_to_dbus_fcn) || prop_info->param_spec);
|
|
|
|
|
nm_assert (!_PROPERT_EXTRA (prop_info, gprop_from_dbus_fcn) || 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
|
|
|
|
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
|
|
|
#undef _PROPERT_EXTRA
|
2014-07-29 18:25:10 -04:00
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
c_name = strcmp (a->name, b->name);
|
|
|
|
|
nm_assert (c_name != 0);
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
|
|
|
|
|
/* 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,
|
|
|
|
|
guint property_infos_len,
|
|
|
|
|
NMSettingClass *setting_class)
|
|
|
|
|
{
|
|
|
|
|
const NMSettInfoProperty **arr;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
#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;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
_nm_setting_class_commit_full (NMSettingClass *setting_class,
|
|
|
|
|
NMMetaSettingType meta_type,
|
|
|
|
|
const NMSettInfoSettDetail *detail,
|
|
|
|
|
GArray *properties_override)
|
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;
|
|
|
|
|
gs_free GParamSpec **property_specs = NULL;
|
|
|
|
|
guint i, n_property_specs, override_len;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if (!properties_override) {
|
|
|
|
|
override_len = 0;
|
|
|
|
|
properties_override = _nm_sett_info_property_override_create_array ();
|
|
|
|
|
} else
|
|
|
|
|
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
|
|
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
for (i = 0; i < properties_override->len; i++) {
|
|
|
|
|
NMSettInfoProperty *p = &g_array_index (properties_override, NMSettInfoProperty, i);
|
|
|
|
|
|
|
|
|
|
nm_assert ((!!p->name) != (!!p->param_spec));
|
|
|
|
|
|
|
|
|
|
if (!p->name) {
|
|
|
|
|
nm_assert (p->param_spec);
|
|
|
|
|
p->name = p->param_spec->name;
|
|
|
|
|
} else
|
|
|
|
|
nm_assert (!p->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
|
|
|
#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;
|
|
|
|
|
guint 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_sett_info_property_find_in_array ((NMSettInfoProperty *) properties_override->data,
|
|
|
|
|
i,
|
|
|
|
|
p->name));
|
|
|
|
|
for (j = 0; j < n_property_specs; j++) {
|
2019-01-04 15:37:39 +01:00
|
|
|
if (!nm_streq (property_specs[j]->name, p->name))
|
|
|
|
|
continue;
|
|
|
|
|
nm_assert (!found);
|
|
|
|
|
found = TRUE;
|
|
|
|
|
nm_assert (p->param_spec == property_specs[j]);
|
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;
|
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
|
|
|
if (_nm_sett_info_property_find_in_array ((NMSettInfoProperty *) properties_override->data,
|
|
|
|
|
override_len,
|
|
|
|
|
name))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
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;
|
2019-04-24 15:51:04 +02:00
|
|
|
|
|
|
|
|
nm_assert (p->param_spec);
|
|
|
|
|
|
|
|
|
|
vtype = p->param_spec->value_type;
|
|
|
|
|
if (vtype == G_TYPE_BOOLEAN)
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_BOOLEAN);
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_UCHAR)
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_BYTE);
|
2019-04-24 15:51:04 +02:00
|
|
|
else 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)
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_INT64);
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_UINT64)
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_UINT64);
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_STRING)
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_STRING);
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_DOUBLE)
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_DOUBLE);
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_STRV)
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_STRING_ARRAY);
|
2019-04-24 15:51:04 +02:00
|
|
|
else if (vtype == G_TYPE_BYTES) {
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_BYTESTRING,
|
|
|
|
|
.gprop_to_dbus_fcn = _gprop_to_dbus_fcn_bytes);
|
2019-04-24 15:51:04 +02:00
|
|
|
} else if (g_type_is_a (vtype, G_TYPE_ENUM)) {
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_INT32,
|
|
|
|
|
.gprop_to_dbus_fcn = _gprop_to_dbus_fcn_enum);
|
2019-04-24 15:51:04 +02:00
|
|
|
} else if (g_type_is_a (vtype, G_TYPE_FLAGS)) {
|
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
|
|
|
p->property_type = NM_SETT_INFO_PROPERT_TYPE (.dbus_type = G_VARIANT_TYPE_UINT32,
|
|
|
|
|
.gprop_to_dbus_fcn = _gprop_to_dbus_fcn_flags);
|
|
|
|
|
} 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;
|
|
|
|
|
if (detail)
|
|
|
|
|
sett_info->detail = *detail;
|
2019-09-22 16:21:00 +02:00
|
|
|
nm_assert (properties_override->len > 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
|
|
|
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
|
|
|
|
|
|
|
|
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
|
|
|
{
|
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;
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
property = &sett_info->property_infos[idx];
|
|
|
|
|
|
|
|
|
|
nm_assert (idx == 0 || strcmp (property[-1].name, property[0].name) < 0);
|
|
|
|
|
nm_assert (idx == sett_info->property_infos_len - 1 || strcmp (property[0].name, property[1].name) < 0);
|
|
|
|
|
|
|
|
|
|
return property;
|
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
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
GVariant *setting_dict, *value;
|
|
|
|
|
|
|
|
|
|
setting_dict = g_variant_lookup_value (connection_dict, nm_setting_get_name (NM_SETTING (setting)), NM_VARIANT_TYPE_SETTING);
|
|
|
|
|
g_return_val_if_fail (setting_dict != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
/* If the new property isn't set, we have to use the legacy property. */
|
|
|
|
|
value = g_variant_lookup_value (setting_dict, new_property, NULL);
|
|
|
|
|
if (!value) {
|
|
|
|
|
g_variant_unref (setting_dict);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
g_variant_unref (value);
|
|
|
|
|
|
|
|
|
|
/* Otherwise, clients always prefer new properties sent from the daemon. */
|
|
|
|
|
if (!_nm_utils_is_manager_process) {
|
|
|
|
|
g_variant_unref (setting_dict);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The daemon prefers the legacy property if it exists. */
|
|
|
|
|
value = g_variant_lookup_value (setting_dict, legacy_property, NULL);
|
|
|
|
|
g_variant_unref (setting_dict);
|
|
|
|
|
|
|
|
|
|
if (value) {
|
|
|
|
|
g_variant_unref (value);
|
|
|
|
|
return TRUE;
|
|
|
|
|
} else
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
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,
|
|
|
|
|
guint property_idx,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
NMConnectionSerializationFlags flags,
|
2019-06-27 09:07:16 +02:00
|
|
|
const NMConnectionSerializationOptions *options,
|
2019-04-24 17:41:32 +02:00
|
|
|
gboolean ignore_flags,
|
|
|
|
|
gboolean ignore_default)
|
2014-08-16 10:09:48 -04:00
|
|
|
{
|
2019-04-24 17:41:32 +02:00
|
|
|
const NMSettInfoProperty *property = &sett_info->property_infos[property_idx];
|
2019-04-24 15:51:04 +02:00
|
|
|
GVariant *variant;
|
|
|
|
|
|
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 (property->property_type->dbus_type);
|
2014-08-16 10:09:48 -04:00
|
|
|
|
2019-04-24 17:41:32 +02:00
|
|
|
if (!property->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
|
|
|
if (!property->property_type->to_dbus_fcn)
|
2019-04-24 17:41:32 +02:00
|
|
|
return NULL;
|
2019-09-24 18:25:00 +02:00
|
|
|
} else if ( !ignore_flags
|
|
|
|
|
&& !NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_TO_DBUS_IGNORE_FLAGS)) {
|
2019-04-24 17:41:32 +02:00
|
|
|
if (!NM_FLAGS_HAS (property->param_spec->flags, G_PARAM_WRITABLE))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if ( NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_LEGACY)
|
|
|
|
|
&& !_nm_utils_is_manager_process)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2019-06-15 11:18:46 +02:00
|
|
|
if (NM_FLAGS_HAS (property->param_spec->flags, NM_SETTING_PARAM_SECRET)) {
|
|
|
|
|
if (NM_FLAGS_HAS (flags, NM_CONNECTION_SERIALIZE_NO_SECRETS))
|
|
|
|
|
return NULL;
|
2019-09-19 20:28:03 +02:00
|
|
|
|
2019-09-24 18:25:00 +02:00
|
|
|
if (NM_FLAGS_HAS (flags, NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED)) {
|
2019-06-15 11:18:46 +02:00
|
|
|
NMSettingSecretFlags f;
|
|
|
|
|
|
|
|
|
|
/* see also _nm_connection_serialize_secrets() */
|
|
|
|
|
if (!nm_setting_get_secret_flags (setting, property->param_spec->name, &f, NULL))
|
|
|
|
|
return NULL;
|
|
|
|
|
if (!NM_FLAGS_HAS (f, NM_SETTING_SECRET_FLAG_AGENT_OWNED))
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (NM_FLAGS_HAS (flags, NM_CONNECTION_SERIALIZE_ONLY_SECRETS))
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2019-04-24 17:41:32 +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 (property->property_type->to_dbus_fcn) {
|
|
|
|
|
variant = property->property_type->to_dbus_fcn (sett_info, property_idx, connection, setting, flags, options);
|
2019-04-24 15:51:04 +02:00
|
|
|
nm_g_variant_take_ref (variant);
|
|
|
|
|
} else {
|
2019-04-24 15:10:41 +02:00
|
|
|
nm_auto_unset_gvalue GValue prop_value = { 0, };
|
2014-08-16 10:09:48 -04:00
|
|
|
|
2019-04-24 15:51:04 +02:00
|
|
|
nm_assert (property->param_spec);
|
|
|
|
|
|
2019-04-24 15:10:41 +02:00
|
|
|
g_value_init (&prop_value, property->param_spec->value_type);
|
|
|
|
|
|
|
|
|
|
g_object_get_property (G_OBJECT (setting), property->param_spec->name, &prop_value);
|
2014-08-16 10:09:48 -04:00
|
|
|
|
2019-04-24 15:10:41 +02:00
|
|
|
if ( ignore_default
|
|
|
|
|
&& g_param_value_defaults (property->param_spec, &prop_value))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
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 (property->property_type->gprop_to_dbus_fcn) {
|
|
|
|
|
variant = property->property_type->gprop_to_dbus_fcn (&prop_value);
|
2019-04-24 15:51:04 +02:00
|
|
|
nm_g_variant_take_ref (variant);
|
|
|
|
|
} else
|
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
|
|
|
variant = g_dbus_gvalue_to_gvariant (&prop_value, property->property_type->dbus_type);
|
2019-04-24 15:51:04 +02:00
|
|
|
}
|
2019-04-24 15:10:41 +02:00
|
|
|
|
2019-04-24 15:51:04 +02:00
|
|
|
nm_assert (!variant || !g_variant_is_floating (variant));
|
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 (!variant || g_variant_is_of_type (variant, property->property_type->dbus_type));
|
2019-04-24 15:10:41 +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
|
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
|
|
|
set_property_from_dbus (const NMSettInfoProperty *property,
|
2015-01-15 12:19:06 -05:00
|
|
|
GVariant *src_value,
|
|
|
|
|
GValue *dst_value)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
2019-04-24 16:28:11 +02:00
|
|
|
nm_assert (property->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
|
|
|
nm_assert (property->property_type->dbus_type);
|
2014-07-24 08:53:33 -04: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 (property->property_type->gprop_from_dbus_fcn) {
|
|
|
|
|
if (!g_variant_type_equal (g_variant_get_type (src_value), property->property_type->dbus_type))
|
2015-01-15 12:19:06 -05:00
|
|
|
return FALSE;
|
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
|
|
|
property->property_type->gprop_from_dbus_fcn (src_value, dst_value);
|
2015-01-15 12:19:06 -05:00
|
|
|
} else if (dst_value->g_type == G_TYPE_BYTES) {
|
|
|
|
|
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);
|
2015-01-15 12:19:06 -05:00
|
|
|
} else {
|
|
|
|
|
GValue tmp = G_VALUE_INIT;
|
|
|
|
|
|
|
|
|
|
g_dbus_gvariant_to_gvalue (src_value, &tmp);
|
|
|
|
|
if (G_VALUE_TYPE (&tmp) == G_VALUE_TYPE (dst_value))
|
|
|
|
|
*dst_value = tmp;
|
|
|
|
|
else {
|
|
|
|
|
gboolean success;
|
|
|
|
|
|
|
|
|
|
success = g_value_transform (&tmp, dst_value);
|
|
|
|
|
g_value_unset (&tmp);
|
|
|
|
|
if (!success)
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
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;
|
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 n_properties, i;
|
|
|
|
|
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
|
|
|
|
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
|
|
|
n_properties = _nm_setting_gendata_get_all (setting, &gendata_keys, NULL);
|
|
|
|
|
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));
|
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-04-24 17:41:32 +02:00
|
|
|
gs_unref_variant GVariant *dbus_value = NULL;
|
2019-01-02 15:54:18 +01:00
|
|
|
|
2019-06-27 09:07:16 +02:00
|
|
|
dbus_value = property_to_dbus (sett_info, i, connection, setting, flags, options, FALSE, TRUE);
|
2014-08-16 10:09:48 -04:00
|
|
|
if (dbus_value) {
|
2019-04-24 17:41:32 +02:00
|
|
|
g_variant_builder_add (&builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
sett_info->property_infos[i].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.
|
|
|
|
|
*/
|
2014-08-04 11:39:33 -04:00
|
|
|
setting = (NMSetting *) g_object_new (setting_type, NULL);
|
2014-05-09 15:02:57 -04: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;
|
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
|
|
|
|
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);
|
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);
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if ( NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)
|
|
|
|
|
&& g_hash_table_size (keys) > 0) {
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
const char *key;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_steal_pointer (&setting);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_nm_setting_gendata_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);
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
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;
|
2015-01-15 10:56:02 -05:00
|
|
|
|
2019-01-11 14:10:15 +01:00
|
|
|
if ( property_info->param_spec
|
|
|
|
|
&& !(property_info->param_spec->flags & G_PARAM_WRITABLE))
|
2015-01-15 10:56:02 -05:00
|
|
|
continue;
|
|
|
|
|
|
2019-01-11 14:10:15 +01:00
|
|
|
value = g_variant_lookup_value (setting_dict, property_info->name, NULL);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-05-13 12:22:40 +02:00
|
|
|
if ( value
|
|
|
|
|
&& keys)
|
2019-01-11 14:10:15 +01:00
|
|
|
g_hash_table_remove (keys, property_info->name);
|
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
|
|
|
|
2019-01-11 14:10:15 +01:00
|
|
|
if ( value
|
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
|
|
|
&& property_info->property_type->from_dbus_fcn) {
|
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
|
|
|
|
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 (value), property_info->property_type->dbus_type)) {
|
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
|
|
|
/* for backward behavior, fail unless best-effort is chosen. */
|
|
|
|
|
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
|
|
|
|
|
continue;
|
2015-01-15 12:19:06 -05:00
|
|
|
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("can't set property of type '%s' from value of type '%s'"),
|
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
|
|
|
property_info->property_type->dbus_type ?
|
|
|
|
|
g_variant_type_peek_string (property_info->property_type->dbus_type) :
|
2019-01-11 14:10:15 +01:00
|
|
|
property_info->param_spec ?
|
|
|
|
|
g_type_name (property_info->param_spec->value_type) : "(unknown)",
|
2015-01-15 12:19:06 -05:00
|
|
|
g_variant_get_type_string (value));
|
2019-01-11 14:10:15 +01:00
|
|
|
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
|
2019-05-13 12:22:40 +02:00
|
|
|
return FALSE;
|
2015-01-15 12:19:06 -05: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 (!property_info->property_type->from_dbus_fcn (setting,
|
|
|
|
|
connection_dict,
|
|
|
|
|
property_info->name,
|
|
|
|
|
value,
|
|
|
|
|
parse_flags,
|
|
|
|
|
&local)) {
|
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))
|
|
|
|
|
continue;
|
|
|
|
|
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("failed to set property: %s"),
|
|
|
|
|
local->message);
|
2019-01-11 14:10:15 +01:00
|
|
|
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
|
2019-05-13 12:22:40 +02:00
|
|
|
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
|
|
|
}
|
2019-01-11 14:10:15 +01:00
|
|
|
} else if ( !value
|
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
|
|
|
&& property_info->property_type->missing_from_dbus_fcn) {
|
|
|
|
|
if (!property_info->property_type->missing_from_dbus_fcn (setting,
|
|
|
|
|
connection_dict,
|
|
|
|
|
property_info->name,
|
|
|
|
|
parse_flags,
|
|
|
|
|
&local)) {
|
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))
|
|
|
|
|
continue;
|
|
|
|
|
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("failed to set property: %s"),
|
|
|
|
|
local->message);
|
2019-01-11 14:10:15 +01:00
|
|
|
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
|
2019-05-13 12:22:40 +02:00
|
|
|
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
|
|
|
}
|
2019-01-11 14:10:15 +01:00
|
|
|
} else if ( value
|
|
|
|
|
&& property_info->param_spec) {
|
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_auto_unset_gvalue GValue object_value = G_VALUE_INIT;
|
2014-08-16 10:09:48 -04:00
|
|
|
|
2019-01-11 14:10:15 +01:00
|
|
|
g_value_init (&object_value, property_info->param_spec->value_type);
|
|
|
|
|
if (!set_property_from_dbus (property_info, value, &object_value)) {
|
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
|
|
|
/* for backward behavior, fail unless best-effort is chosen. */
|
|
|
|
|
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
|
|
|
|
|
continue;
|
|
|
|
|
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("can't set property of type '%s' from value of type '%s'"),
|
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
|
|
|
property_info->property_type->dbus_type
|
|
|
|
|
? g_variant_type_peek_string (property_info->property_type->dbus_type)
|
2019-01-11 14:10:15 +01:00
|
|
|
: ( property_info->param_spec
|
|
|
|
|
? g_type_name (property_info->param_spec->value_type)
|
|
|
|
|
: "(unknown)"),
|
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_get_type_string (value));
|
2019-01-11 14:10:15 +01:00
|
|
|
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
|
2019-05-13 12:22:40 +02:00
|
|
|
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
|
|
|
}
|
2015-01-15 12:19:06 -05:00
|
|
|
|
2019-01-11 14:10:15 +01:00
|
|
|
if (!nm_g_object_set_property (G_OBJECT (setting), property_info->param_spec->name, &object_value, &local)) {
|
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))
|
|
|
|
|
continue;
|
|
|
|
|
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("can not set property: %s"),
|
|
|
|
|
local->message);
|
2019-01-11 14:10:15 +01:00
|
|
|
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
|
2019-05-13 12:22:40 +02:00
|
|
|
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
|
|
|
}
|
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-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
|
|
|
}
|
2014-08-16 10:09:48 -04: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)
|
|
|
|
|
{
|
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;
|
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);
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
property = _nm_setting_class_get_property_info (NM_SETTING_GET_CLASS (setting), property_name);
|
2019-04-24 15:10:41 +02:00
|
|
|
|
2014-11-16 16:13:06 -05:00
|
|
|
g_return_val_if_fail (property != NULL, NULL);
|
|
|
|
|
|
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 (property->property_type);
|
|
|
|
|
nm_assert (g_variant_type_string_is_valid ((const char *) property->property_type->dbus_type));
|
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
|
|
|
return property->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
|
|
|
{
|
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);
|
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-20 14:01:24 +01:00
|
|
|
nm_assert (!_gendata_hash (dst, FALSE));
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-04 14:37:30 +01:00
|
|
|
|
|
|
|
|
if (sett_info->property_infos_len > 0) {
|
|
|
|
|
gboolean frozen = FALSE;
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2019-01-11 15:16:33 +01:00
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
|
2019-01-04 14:37:30 +01:00
|
|
|
|
2019-01-11 15:16:33 +01:00
|
|
|
if (property_info->param_spec) {
|
|
|
|
|
if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE)
|
|
|
|
|
continue;
|
2019-01-04 14:37:30 +01:00
|
|
|
|
2019-01-11 15:16:33 +01:00
|
|
|
if (!frozen) {
|
|
|
|
|
g_object_freeze_notify (G_OBJECT (dst));
|
|
|
|
|
frozen = TRUE;
|
|
|
|
|
}
|
|
|
|
|
_gobject_copy_property (G_OBJECT (src),
|
|
|
|
|
G_OBJECT (dst),
|
|
|
|
|
property_info->param_spec->name,
|
|
|
|
|
G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec));
|
|
|
|
|
continue;
|
2019-01-04 14:37:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (frozen)
|
2019-01-11 15:16:33 +01:00
|
|
|
g_object_thaw_notify (G_OBJECT (dst));
|
2019-01-04 14:37:30 +01:00
|
|
|
}
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMTernary
|
|
|
|
|
compare_property (const NMSettInfoSetting *sett_info,
|
|
|
|
|
guint property_idx,
|
2019-04-25 10:17:47 +02:00
|
|
|
NMConnection *con_a,
|
|
|
|
|
NMSetting *set_a,
|
|
|
|
|
NMConnection *con_b,
|
|
|
|
|
NMSetting *set_b,
|
2014-07-24 08:53:33 -04:00
|
|
|
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
|
|
|
const NMSettInfoProperty *property_info = &sett_info->property_infos[property_idx];
|
|
|
|
|
const GParamSpec *param_spec = property_info->param_spec;
|
|
|
|
|
|
|
|
|
|
if (!param_spec)
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
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
|
|
|
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 NM_TERNARY_DEFAULT;
|
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
|
|
|
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
|
|
|
|
|
&& !NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_INFERRABLE))
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
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
|
|
|
|
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_REAPPLY_IMMEDIATELY)
|
|
|
|
|
&& NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_REAPPLY_IMMEDIATELY))
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
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
|
|
|
if ( NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS)
|
|
|
|
|
&& NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET))
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
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
|
|
|
if (nm_streq (param_spec->name, NM_SETTING_NAME))
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
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
|
|
|
if ( NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET)
|
2019-04-25 10:17:47 +02:00
|
|
|
&& !_nm_setting_should_compare_secret_property (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
|
|
|
param_spec->name,
|
|
|
|
|
flags))
|
|
|
|
|
return NM_TERNARY_DEFAULT;
|
2014-07-24 08:53:33 -04:00
|
|
|
|
2019-04-25 10:17:47 +02:00
|
|
|
if (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
|
|
|
gs_unref_variant GVariant *value1 = NULL;
|
|
|
|
|
gs_unref_variant GVariant *value2 = NULL;
|
2014-07-30 10:46:24 -04:00
|
|
|
|
2019-06-27 09:07:16 +02:00
|
|
|
value1 = property_to_dbus (sett_info, property_idx, con_a, set_a, NM_CONNECTION_SERIALIZE_ALL, NULL, TRUE, TRUE);
|
|
|
|
|
value2 = property_to_dbus (sett_info, property_idx, con_b, set_b, NM_CONNECTION_SERIALIZE_ALL, NULL, TRUE, 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
|
|
|
if (nm_property_compare (value1, value2) != 0)
|
|
|
|
|
return NM_TERNARY_FALSE;
|
|
|
|
|
}
|
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
|
|
|
return NM_TERNARY_TRUE;
|
|
|
|
|
}
|
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
|
|
|
|
|
_compare_property (const NMSettInfoSetting *sett_info,
|
|
|
|
|
guint property_idx,
|
2019-04-25 10:17:47 +02:00
|
|
|
NMConnection *con_a,
|
|
|
|
|
NMSetting *set_a,
|
|
|
|
|
NMConnection *con_b,
|
|
|
|
|
NMSetting *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
|
|
|
NMSettingCompareFlags flags)
|
|
|
|
|
{
|
|
|
|
|
NMTernary compare_result;
|
|
|
|
|
|
|
|
|
|
nm_assert (sett_info);
|
|
|
|
|
nm_assert (NM_IS_SETTING_CLASS (sett_info->setting_class));
|
|
|
|
|
nm_assert (property_idx < sett_info->property_infos_len);
|
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);
|
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
|
|
|
|
2019-04-25 10:17:47 +02:00
|
|
|
compare_result = NM_SETTING_GET_CLASS (set_a)->compare_property (sett_info,
|
|
|
|
|
property_idx,
|
|
|
|
|
con_a,
|
|
|
|
|
set_a,
|
|
|
|
|
con_b,
|
|
|
|
|
set_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
|
|
|
|
|
|
|
|
nm_assert (NM_IN_SET (compare_result, NM_TERNARY_DEFAULT,
|
|
|
|
|
NM_TERNARY_FALSE,
|
|
|
|
|
NM_TERNARY_TRUE));
|
|
|
|
|
|
|
|
|
|
/* check that the inferable flag and the GObject property flag corresponds. */
|
|
|
|
|
nm_assert ( !NM_FLAGS_HAS (flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)
|
|
|
|
|
|| !sett_info->property_infos[property_idx].param_spec
|
|
|
|
|
|| NM_FLAGS_HAS (sett_info->property_infos[property_idx].param_spec->flags, NM_SETTING_PARAM_INFERRABLE)
|
|
|
|
|
|| compare_result == NM_TERNARY_DEFAULT);
|
|
|
|
|
|
2019-10-10 10:20:50 +02:00
|
|
|
#if NM_MORE_ASSERTS > 10
|
|
|
|
|
/* assert that compare_property() is symeric. */
|
|
|
|
|
nm_assert ( !set_b
|
|
|
|
|
|| compare_result == NM_SETTING_GET_CLASS (set_a)->compare_property (sett_info,
|
|
|
|
|
property_idx,
|
|
|
|
|
con_b,
|
|
|
|
|
set_b,
|
|
|
|
|
con_a,
|
|
|
|
|
set_a,
|
|
|
|
|
flags));
|
|
|
|
|
#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;
|
2014-07-24 08:53:33 -04:00
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
return nm_utils_hash_table_equal (a_gendata ? a_gendata->hash : NULL,
|
|
|
|
|
b_gendata ? b_gendata->hash : NULL,
|
|
|
|
|
TRUE,
|
|
|
|
|
g_variant_equal);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 10:49:50 +01:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2019-04-25 10:17:47 +02:00
|
|
|
if (_compare_property (sett_info, 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
|
|
|
guint i;
|
|
|
|
|
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;
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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-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;
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (a));
|
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
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
if (!a_gendata || !b_gendata) {
|
|
|
|
|
if (a_gendata || b_gendata) {
|
|
|
|
|
NMSettingDiffResult one_sided_result;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} 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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2019-01-04 10:49:50 +01:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; 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
|
|
|
NMSettingDiffResult r = NM_SETTING_DIFF_RESULT_UNKNOWN;
|
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
|
|
|
const NMSettInfoProperty *property_info;
|
|
|
|
|
NMTernary compare_result;
|
|
|
|
|
GParamSpec *prop_spec;
|
2017-10-26 13:25:54 +02:00
|
|
|
|
2019-04-25 10:17:47 +02:00
|
|
|
compare_result = _compare_property (sett_info, i, 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;
|
|
|
|
|
|
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. */
|
2019-04-25 10:17:47 +02:00
|
|
|
if (_compare_property (sett_info, i, con_a, a, NULL, NULL, flags) == 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;
|
|
|
|
|
}
|
2014-02-26 11:26:25 +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
|
|
|
compared_any = 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
|
|
|
property_info = &sett_info->property_infos[i];
|
|
|
|
|
prop_spec = property_info->param_spec;
|
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: 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;
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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;
|
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
|
|
|
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;
|
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
|
|
|
g_value_unset (&value);
|
|
|
|
|
} else
|
|
|
|
|
r |= a_result;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2014-02-26 11:26:25 +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 (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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
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. */
|
|
|
|
|
n_properties = _nm_setting_gendata_get_all (setting, &names, NULL);
|
|
|
|
|
if (n_properties > 0) {
|
|
|
|
|
gs_strfreev char **keys = g_strdupv ((char **) names);
|
|
|
|
|
GHashTable *h = _gendata_hash (setting, FALSE)->hash;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n_properties; i++) {
|
|
|
|
|
GValue value = G_VALUE_INIT;
|
|
|
|
|
GVariant *val = g_hash_table_lookup (h, keys[i]);
|
|
|
|
|
|
|
|
|
|
if (!val) {
|
|
|
|
|
/* was deleted in the meantime? Skip */
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-04 10:49:50 +01:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2019-01-21 08:10:14 +01:00
|
|
|
NM_SETTING_GET_CLASS (setting)->enumerate_values (_nm_sett_info_property_info_get_sorted (sett_info, i),
|
|
|
|
|
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;
|
|
|
|
|
guint i;
|
|
|
|
|
|
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));
|
2019-01-04 11:28:27 +01: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;
|
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* for the moment, all aggregate types only care about secrets. */
|
|
|
|
|
nm_assert (nm_setting_get_secret_flags (setting, property_info->name, NULL, NULL));
|
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;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
guint property_idx,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
NMSettingClearSecretsWithFlagsFn func,
|
|
|
|
|
gpointer user_data)
|
2014-07-24 08:53:33 -04:00
|
|
|
{
|
|
|
|
|
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
|
2019-01-13 21:23:02 +01:00
|
|
|
GParamSpec *param_spec = sett_info->property_infos[property_idx].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;
|
2019-01-04 10:49:50 +01:00
|
|
|
guint i;
|
2019-01-13 21:23:02 +01:00
|
|
|
gboolean (*my_clear_secrets) (const struct _NMSettInfoSetting *sett_info,
|
|
|
|
|
guint property_idx,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
NMSettingClearSecretsWithFlagsFn func,
|
|
|
|
|
gpointer user_data);
|
2014-07-24 08:53:33 -04:00
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
|
|
|
|
|
|
2019-01-13 21:23:02 +01:00
|
|
|
my_clear_secrets = NM_SETTING_GET_CLASS (setting)->clear_secrets;
|
|
|
|
|
|
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++) {
|
2019-01-13 21:23:02 +01:00
|
|
|
changed |= my_clear_secrets (sett_info,
|
|
|
|
|
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: 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;
|
2014-07-24 08:53:33 -04:00
|
|
|
GParamSpec *prop_spec;
|
2014-08-16 10:09:48 -04:00
|
|
|
GValue prop_value = { 0, };
|
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), key);
|
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
|
|
|
if (!property) {
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Silently ignore non-secrets */
|
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
|
|
|
prop_spec = property->param_spec;
|
|
|
|
|
if (!prop_spec || !(prop_spec->flags & NM_SETTING_PARAM_SECRET))
|
2014-07-24 08:53:33 -04:00
|
|
|
return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
|
|
|
|
|
|
2014-08-16 10:09:48 -04:00
|
|
|
if ( g_variant_is_of_type (value, G_VARIANT_TYPE_STRING)
|
|
|
|
|
&& G_IS_PARAM_SPEC_STRING (prop_spec)) {
|
|
|
|
|
/* String is expected to be a common case. Handle it specially and check
|
|
|
|
|
* whether the value is already set. Otherwise, we just reset the
|
|
|
|
|
* property and assume the value got modified.
|
|
|
|
|
*/
|
|
|
|
|
char *v;
|
|
|
|
|
|
|
|
|
|
g_object_get (G_OBJECT (setting), prop_spec->name, &v, NULL);
|
|
|
|
|
if (g_strcmp0 (v, g_variant_get_string (value, NULL)) == 0) {
|
2014-07-24 08:53:33 -04:00
|
|
|
g_free (v);
|
2014-08-16 10:09:48 -04:00
|
|
|
return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2014-08-16 10:09:48 -04:00
|
|
|
g_free (v);
|
2014-07-24 08:53:33 -04:00
|
|
|
}
|
2014-08-16 10:09:48 -04:00
|
|
|
|
|
|
|
|
g_value_init (&prop_value, prop_spec->value_type);
|
|
|
|
|
set_property_from_dbus (property, value, &prop_value);
|
|
|
|
|
g_object_set_property (G_OBJECT (setting), prop_spec->name, &prop_value);
|
|
|
|
|
g_value_unset (&prop_value);
|
|
|
|
|
|
|
|
|
|
return NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
|
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),
|
2019-01-06 13:49:46 +01:00
|
|
|
secret_flags_name,
|
2017-11-20 13:52:18 +01:00
|
|
|
&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 *
|
2019-01-02 15:54:18 +01:00
|
|
|
_nm_setting_get_deprecated_virtual_interface_name (const NMSettInfoSetting *sett_info,
|
|
|
|
|
guint property_idx,
|
2014-08-04 19:57:20 -04:00
|
|
|
NMConnection *connection,
|
2019-01-02 15:54:18 +01:00
|
|
|
NMSetting *setting,
|
2019-06-27 09:07:16 +02:00
|
|
|
NMConnectionSerializationFlags flags,
|
|
|
|
|
const NMConnectionSerializationOptions *options)
|
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
|
|
|
}
|
|
|
|
|
|
2019-09-22 10:57:57 +02:00
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_interface_name = {
|
|
|
|
|
.dbus_type = G_VARIANT_TYPE_STRING,
|
|
|
|
|
.to_dbus_fcn = _nm_setting_get_deprecated_virtual_interface_name,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_ignore_i = {
|
|
|
|
|
.dbus_type = G_VARIANT_TYPE_INT32,
|
|
|
|
|
/* No functions set. This property type is to silently ignore the value on D-Bus. */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_deprecated_ignore_u = {
|
|
|
|
|
.dbus_type = G_VARIANT_TYPE_UINT32,
|
|
|
|
|
/* No functions set. This property type is to silently ignore the value on D-Bus. */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_plain_i = {
|
|
|
|
|
.dbus_type = G_VARIANT_TYPE_INT32,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const NMSettInfoPropertType nm_sett_info_propert_type_plain_u = {
|
|
|
|
|
.dbus_type = G_VARIANT_TYPE_UINT32,
|
|
|
|
|
};
|
|
|
|
|
|
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 *
|
|
|
|
|
_nm_setting_gendata_hash (NMSetting *setting, gboolean create_if_necessary)
|
|
|
|
|
{
|
|
|
|
|
GenData *gendata;
|
|
|
|
|
|
|
|
|
|
gendata = _gendata_hash (setting, create_if_necessary);
|
|
|
|
|
return gendata ? gendata->hash : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_nm_setting_gendata_notify (NMSetting *setting,
|
|
|
|
|
gboolean names_changed)
|
|
|
|
|
{
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_setting_gendata_get (NMSetting *setting,
|
|
|
|
|
const char *name)
|
|
|
|
|
{
|
|
|
|
|
GenData *gendata;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
|
|
|
|
|
g_return_val_if_fail (name, NULL);
|
|
|
|
|
|
|
|
|
|
gendata = _gendata_hash (setting, FALSE);
|
|
|
|
|
return gendata ? g_hash_table_lookup (gendata->hash, name) : NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guint
|
|
|
|
|
_nm_setting_gendata_get_all (NMSetting *setting,
|
|
|
|
|
const char *const**out_names,
|
|
|
|
|
GVariant *const**out_values)
|
|
|
|
|
{
|
|
|
|
|
GenData *gendata;
|
|
|
|
|
GHashTable *hash;
|
|
|
|
|
guint i, len;
|
|
|
|
|
|
|
|
|
|
nm_assert (NM_IS_SETTING (setting));
|
|
|
|
|
|
|
|
|
|
gendata = _gendata_hash (setting, FALSE);
|
|
|
|
|
if (!gendata)
|
|
|
|
|
goto out_zero;
|
|
|
|
|
|
|
|
|
|
hash = gendata->hash;
|
|
|
|
|
len = g_hash_table_size (hash);
|
|
|
|
|
if (len == 0)
|
|
|
|
|
goto out_zero;
|
|
|
|
|
|
|
|
|
|
if (!out_names && !out_values)
|
|
|
|
|
return len;
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY (!gendata->names)) {
|
|
|
|
|
gendata->names = nm_utils_strdict_get_keys (hash,
|
|
|
|
|
TRUE,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_gendata_get_all_names:
|
|
|
|
|
* @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
|
|
|
*
|
|
|
|
|
* Gives the number of generic data elements and optionally returns all their
|
|
|
|
|
* key names and values. This API is low level access and unless you know what you
|
|
|
|
|
* are doing, it might not be what you want.
|
|
|
|
|
*
|
|
|
|
|
* 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
|
|
|
|
|
* soon.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.14
|
|
|
|
|
**/
|
|
|
|
|
const char *const*
|
|
|
|
|
nm_setting_gendata_get_all_names (NMSetting *setting,
|
|
|
|
|
guint *out_len)
|
|
|
|
|
{
|
|
|
|
|
const char *const*names;
|
|
|
|
|
guint len;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
|
|
|
|
|
|
|
|
|
|
len = _nm_setting_gendata_get_all (setting, &names, NULL);
|
|
|
|
|
NM_SET_OUT (out_len, len);
|
|
|
|
|
return names;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_gendata_get_all_values:
|
|
|
|
|
* @setting: the #NMSetting
|
|
|
|
|
*
|
|
|
|
|
* Gives the number of generic data elements and optionally returns all their
|
|
|
|
|
* key names and values. This API is low level access and unless you know what you
|
|
|
|
|
* are doing, it might not be what you want.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (array zero-terminated=1) (transfer none):
|
|
|
|
|
* A %NULL terminated array of #GVariant. If no data is present, this returns
|
|
|
|
|
* %NULL. The returned array and the variants are owned by %NMSetting and might be invalidated
|
|
|
|
|
* soon. The sort order of nm_setting_gendata_get_all_names() and nm_setting_gendata_get_all_values()
|
|
|
|
|
* is consistent. That means, the nth value has the nth name returned by nm_setting_gendata_get_all_names().
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.14
|
|
|
|
|
**/
|
|
|
|
|
GVariant *const*
|
|
|
|
|
nm_setting_gendata_get_all_values (NMSetting *setting)
|
|
|
|
|
{
|
|
|
|
|
GVariant *const*values;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
|
|
|
|
|
|
|
|
|
|
_nm_setting_gendata_get_all (setting, NULL, &values);
|
|
|
|
|
return values;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
_nm_setting_gendata_to_gvalue (NMSetting *setting,
|
2019-01-20 14:01:24 +01:00
|
|
|
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
|
|
|
{
|
|
|
|
|
GenData *gendata;
|
|
|
|
|
GHashTable *new;
|
|
|
|
|
const char *key;
|
|
|
|
|
GVariant *val;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
|
|
|
|
|
nm_assert (NM_IS_SETTING (setting));
|
|
|
|
|
nm_assert (value);
|
|
|
|
|
nm_assert (G_TYPE_CHECK_VALUE_TYPE ((value), G_TYPE_HASH_TABLE));
|
|
|
|
|
|
|
|
|
|
new = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
|
|
|
|
|
|
|
|
|
|
gendata = _gendata_hash (setting, FALSE);
|
|
|
|
|
if (gendata) {
|
|
|
|
|
g_hash_table_iter_init (&iter, gendata->hash);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val))
|
|
|
|
|
g_hash_table_insert (new, g_strdup (key), g_variant_ref (val));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_value_take_boxed (value, new);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
|
_nm_setting_gendata_reset_from_hash (NMSetting *setting,
|
|
|
|
|
GHashTable *new)
|
|
|
|
|
{
|
|
|
|
|
GenData *gendata;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
const char *key;
|
|
|
|
|
GVariant *val;
|
|
|
|
|
guint num;
|
|
|
|
|
|
|
|
|
|
nm_assert (NM_IS_SETTING (setting));
|
|
|
|
|
nm_assert (new);
|
|
|
|
|
|
|
|
|
|
num = new ? g_hash_table_size (new) : 0;
|
|
|
|
|
|
|
|
|
|
gendata = _gendata_hash (setting, num > 0);
|
|
|
|
|
|
|
|
|
|
if (num == 0) {
|
|
|
|
|
if ( !gendata
|
|
|
|
|
|| g_hash_table_size (gendata->hash) == 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
g_hash_table_remove_all (gendata->hash);
|
|
|
|
|
_nm_setting_gendata_notify (setting, TRUE);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* let's not bother to find out whether the new hash has any different
|
2019-01-11 17:07:03 -02:00
|
|
|
* content the current gendata. Just replace it. */
|
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_remove_all (gendata->hash);
|
|
|
|
|
if (num > 0) {
|
|
|
|
|
g_hash_table_iter_init (&iter, new);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val))
|
|
|
|
|
g_hash_table_insert (gendata->hash, g_strdup (key), g_variant_ref (val));
|
|
|
|
|
}
|
|
|
|
|
_nm_setting_gendata_notify (setting, TRUE);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-15 15:25:30 +02:00
|
|
|
gboolean
|
|
|
|
|
nm_setting_gendata_get_uint32 (NMSetting *setting,
|
|
|
|
|
const char *optname,
|
|
|
|
|
guint32 *out_value)
|
|
|
|
|
{
|
|
|
|
|
GVariant *v;
|
|
|
|
|
|
|
|
|
|
nm_assert (NM_IS_SETTING (setting));
|
|
|
|
|
nm_assert (nm_str_not_empty (optname));
|
|
|
|
|
|
|
|
|
|
v = nm_setting_gendata_get (setting, optname);
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nm_setting_gendata_set_uint32 (NMSetting *setting,
|
|
|
|
|
const char *optname,
|
|
|
|
|
guint32 value)
|
|
|
|
|
{
|
|
|
|
|
nm_assert (NM_IS_SETTING (setting));
|
|
|
|
|
nm_assert (nm_str_not_empty (optname));
|
|
|
|
|
|
|
|
|
|
g_hash_table_insert (_nm_setting_gendata_hash (setting, TRUE),
|
|
|
|
|
g_strdup (optname),
|
|
|
|
|
g_variant_ref_sink (g_variant_new_uint32 (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
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
NMSettingPrivate *priv = NM_SETTING_GET_PRIVATE (object);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
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));
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
setting_class->compare_property = compare_property;
|
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
|
|
|
}
|