add a NM_DISPATCHER_ACTION_DHCP_CHANGE_X() macro that can select the
right action based on a parameter.
Also rename the IPv4/IPv6 enum values, so that their naming scheme works
better with the NM_DISPATCHER_ACTION_DHCP_CHANGE_X() macro.
We call add/remove pending actions for every state change.
I think GSList is never the best choice of a data structure. Use a plain
array instead. Keep it sorted, so we can use binary search.
The point is rather special, and the macros themselves are basically
simple wrappers around memmove().
When having a sorted array (for example, a strv array that is searched
using nm_strv_find_binary_search()), then we want to insert/remove
elements at a particular place (via memmove()).
Getting the memmove() arguments is not terribly hard, but hard enough to
add two helper macros for that.
Like nm_utils_addr_family_to_char(), but gives a different treatment to
AF_UNSPEC to return "" instead of 'X'. As such, it also needs to
return a string and not a char.
The advantage of environment variables is that the user can use
`systemctl edit NetworkManager-dispatcher.service` for setting them,
without need to change the ExecStart= line.
Also, enabling debugging from the start is useful, despite that debug
logging can be enabled per-request.
Also, there is a difference whether we want verbose logging or whether
we want to log to stdout. There should be a flag, that only increases the
logging verbosity, but does not change the logging backend.
- exit-on-idle needs to be done correctly. Fix the race, by first
notifying systemd (STOPPING=1), releasing the name, and all the
while continue processing requests.
- don't use g_bus_own_name_on_connection(). That one also listens
to NameLost and NameAcquired signals, but we don't care about those.
systemd will take care to only spawn one process at a time. And
anyway, the well-known name is only important to be reachable, we
don't require it to be functional. We can get the first request
before RequestName completed and we can continue getting requests
after releasing the name.
- use nm_g_timeout_add_source() for millisecond precision of idle timeout.
- schedule the first idle timeout before registering the D-Bus object.
- let the signal handler do nothing, if we are already quitting. In
practice, this only silences the extra logging.
The difference is that nm_g_bus_get_blocking() iterates the GMainContext
of the caller, and thus it can process and handle SIGTERM signals.
Calling g_bus_get_sync() does not iterate the context, and we cannot
handle or detect early cancellation.
Explicitly iterating the context is more flexible, as we can control the
parameters how long we iterate. GMainLoop is essentially a (thread-safe)
iteration around one boolean flag (controlled by g_main_loop_run() and
g_main_loop_quit()). We can maintain that boolean flag ourselves.
GDBus will invoke the method_call callback also for the Get/Set
functions. Thus, we need to check the interface_name and handle
them (actually, there is nothing to handle, no properties exist).
Also, "Ping" method only exists for testing. It is usually not called
in production, so check for "GetFD" first.
Each NML3ConfigData should have a source set, and in fact most callers
would call nm_l3_config_data_set_source() right after creating the
instance.
Move the source parameter to the new() constructor function. Also remove
the setter, making the source of an instance immutable.
As every l3cfg instance generally has a clear purpose, the source should
always be known from the start and doesn't need to change.
Our handling of properties is relatively complicated. We should have
clear code paths and responsibilities who calls who.
There is from_dbus_fcn() callback to implement parsing a GVariant and
set the property in NMSetting. This is called via:
- _nm_setting_new_from_dbus()
- init_from_dbus()
- _property_set_from_dbus()
Then, one of the from_dbus_fcn() implementations is
_nm_setting_property_from_dbus_fcn_gprop(), which calls
set_property_from_dbus(). That one sets the property using GObject
setter. That's good and a clear code path.
However, set_property_from_dbus() was also called via
- _nm_setting_update_secrets()
- klass->update_one_secret()
- nm-setting.c:update_one_secret()
- set_property_from_dbus()
Meaning, there is a different code path to set_property_from_dbus(),
which bypasses from_dbus_fcn(). That is highly undesirable, because
it should be clear how a property setter gets implemented, and this
way, potentially two different implementations were used.
Refactor nm-setting.c:update_one_secret() to use
_property_set_from_dbus() instead. This behaves potentially differently
for properties like NM_SETTING_ADSL_PASSWORD, which is implemented as
a "direct" property, where from_dbus_fcn() setter no longer uses g_object_set().
This should not make a difference in practice, and in any case, now the
code paths are unified.
Note that most implementations use g_object_set(), and it's not
easy to detect modification. In those cases, we assume that modification
happened -- just like also the GObject setter will emit a notification
(as none of our properties use G_PARAM_EXPLICIT_NOTIFY).
These functions tend to have many arguments. They are also quite som
boilerplate to implement the hundereds of properties we have, while
we want that properties have common behaviors and similarities.
Instead of repeatedly spelling out the function arguments, use a macro.
Advantages:
- the usage of a _NM_SETT_INFO_PROP_*_FCN_ARGS macro signals that this
is an implementation of a property. You can now grep for these macros
to find all implementation. That was previously rather imprecise, you
could only `git grep '\.to_dbus_fcn'` to find the uses, but not the
implementations.
As the goal is to keep properties "similar", there is a desire to
reduce the number of similar implementations and to find them.
- changing the arguments now no longer will require you to go through
all implementations. At least not, if you merely add an argument that
has a reasonable default behavior and does not require explicit
handling by most implementation.
- it's convenient to be able to patch the argument list to let the
compiler help to reason about something. For example, the
"connection_dict" argument to from_dbus_fcn() is usually unused.
If you'd like to find who uses it, rename the parameter, and
review the (few) compiler errors.
- it does save 573 LOC of boilerplate with no actual logic or useful
information. I argue, that this simplifies the code and review, by
increasing the relative amount of actually meaningful code.
Disadvantages:
- the user no longer directly sees the argument list. They would need
cscope/ctags or an IDE to jump to the macro definition and conveniently
see all arguments.
Also use _nm_nil, so that clang-format interprets this as a function
parameter list. Otherwise, it formats the function differently.