|
Packit Service |
a1bd4f |
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "nm-default.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "nm-cloud-setup-utils.h"
|
|
Packit |
5756e2 |
|
|
Packit Service |
d0b836 |
#include <linux/if_ether.h>
|
|
Packit Service |
d0b836 |
#include <linux/if_infiniband.h>
|
|
Packit Service |
d0b836 |
|
|
Packit |
5756e2 |
#include "nm-glib-aux/nm-time-utils.h"
|
|
Packit |
5756e2 |
#include "nm-glib-aux/nm-logging-base.h"
|
|
Packit |
5756e2 |
#include "nm-glib-aux/nm-str-buf.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
volatile NMLogLevel _nm_logging_configured_level = LOGL_TRACE;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
void
|
|
Packit Service |
a1bd4f |
_nm_logging_enabled_init(const char *level_str)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMLogLevel level;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (!_nm_log_parse_level(level_str, &level))
|
|
Packit Service |
a1bd4f |
level = LOGL_WARN;
|
|
Packit Service |
a1bd4f |
else if (level == _LOGL_KEEP)
|
|
Packit Service |
a1bd4f |
level = LOGL_WARN;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
_nm_logging_configured_level = level;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
void
|
|
Packit Service |
a1bd4f |
_nm_log_impl_cs(NMLogLevel level, const char *fmt, ...)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_free char *msg = NULL;
|
|
Packit Service |
a1bd4f |
va_list ap;
|
|
Packit Service |
a1bd4f |
const char * level_str;
|
|
Packit Service |
a1bd4f |
gint64 ts;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
va_start(ap, fmt);
|
|
Packit Service |
a1bd4f |
msg = g_strdup_vprintf(fmt, ap);
|
|
Packit Service |
a1bd4f |
va_end(ap);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
switch (level) {
|
|
Packit Service |
a1bd4f |
case LOGL_TRACE:
|
|
Packit Service |
a1bd4f |
level_str = "<trace>";
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
case LOGL_DEBUG:
|
|
Packit Service |
a1bd4f |
level_str = "<debug>";
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
case LOGL_INFO:
|
|
Packit Service |
a1bd4f |
level_str = "<info> ";
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
case LOGL_WARN:
|
|
Packit Service |
a1bd4f |
level_str = "<warn> ";
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
default:
|
|
Packit Service |
a1bd4f |
nm_assert(level == LOGL_ERR);
|
|
Packit Service |
a1bd4f |
level_str = "<error>";
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
ts = nm_utils_clock_gettime_nsec(CLOCK_BOOTTIME);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_print("[%" G_GINT64_FORMAT ".%05" G_GINT64_FORMAT "] %s %s\n",
|
|
Packit Service |
a1bd4f |
ts / NM_UTILS_NSEC_PER_SEC,
|
|
Packit Service |
a1bd4f |
(ts / (NM_UTILS_NSEC_PER_SEC / 10000)) % 10000,
|
|
Packit Service |
a1bd4f |
level_str,
|
|
Packit Service |
a1bd4f |
msg);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
void
|
|
Packit Service |
a1bd4f |
_nm_utils_monotonic_timestamp_initialized(const struct timespec *tp,
|
|
Packit Service |
a1bd4f |
gint64 offset_sec,
|
|
Packit Service |
a1bd4f |
gboolean is_boottime)
|
|
Packit Service |
a1bd4f |
{}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
G_LOCK_DEFINE_STATIC(_wait_for_objects_lock);
|
|
Packit |
5756e2 |
static GSList *_wait_for_objects_list;
|
|
Packit |
5756e2 |
static GSList *_wait_for_objects_iterate_loops;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
_wait_for_objects_maybe_quit_mainloops_with_lock(void)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
GSList *iter;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (!_wait_for_objects_list) {
|
|
Packit Service |
a1bd4f |
for (iter = _wait_for_objects_iterate_loops; iter; iter = iter->next)
|
|
Packit Service |
a1bd4f |
g_main_loop_quit(iter->data);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
_wait_for_objects_weak_cb(gpointer data, GObject *where_the_object_was)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
G_LOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
nm_assert(g_slist_find(_wait_for_objects_list, where_the_object_was));
|
|
Packit Service |
a1bd4f |
_wait_for_objects_list = g_slist_remove(_wait_for_objects_list, where_the_object_was);
|
|
Packit Service |
a1bd4f |
_wait_for_objects_maybe_quit_mainloops_with_lock();
|
|
Packit Service |
a1bd4f |
G_UNLOCK(_wait_for_objects_lock);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nmcs_wait_for_objects_register:
|
|
Packit |
5756e2 |
* @target: a #GObject to wait for.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Registers @target as a pointer to wait during shutdown. Using
|
|
Packit |
5756e2 |
* nmcs_wait_for_objects_iterate_until_done() we keep waiting until
|
|
Packit |
5756e2 |
* @target gets destroyed, which means that it gets completely unreferenced.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
gpointer
|
|
Packit Service |
a1bd4f |
nmcs_wait_for_objects_register(gpointer target)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(G_IS_OBJECT(target), NULL);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
G_LOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
_wait_for_objects_list = g_slist_prepend(_wait_for_objects_list, target);
|
|
Packit Service |
a1bd4f |
G_UNLOCK(_wait_for_objects_lock);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_object_weak_ref(target, _wait_for_objects_weak_cb, NULL);
|
|
Packit Service |
a1bd4f |
return target;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
typedef struct {
|
|
Packit Service |
a1bd4f |
GMainLoop *loop;
|
|
Packit Service |
a1bd4f |
gboolean got_timeout;
|
|
Packit |
5756e2 |
} WaitForObjectsData;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
_wait_for_objects_iterate_until_done_timeout_cb(gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
WaitForObjectsData *data = user_data;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
data->got_timeout = TRUE;
|
|
Packit Service |
a1bd4f |
g_main_loop_quit(data->loop);
|
|
Packit Service |
a1bd4f |
return G_SOURCE_CONTINUE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
_wait_for_objects_iterate_until_done_idle_cb(gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
/* This avoids a race where:
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* - we check whether there are objects to wait for.
|
|
Packit Service |
a1bd4f |
* - the last object to wait for gets removed (issuing g_main_loop_quit()).
|
|
Packit Service |
a1bd4f |
* - we run the mainloop (and missed our signal).
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* It's really a missing feature of GMainLoop where the "is-running" flag is always set to
|
|
Packit Service |
a1bd4f |
* TRUE by g_main_loop_run(). That means, you cannot catch a g_main_loop_quit() in a race
|
|
Packit Service |
a1bd4f |
* free way while not iterating the loop.
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* Avoid this, by checking once again after we start running the mainloop.
|
|
Packit Service |
a1bd4f |
*/
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
G_LOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
_wait_for_objects_maybe_quit_mainloops_with_lock();
|
|
Packit Service |
a1bd4f |
G_UNLOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
return G_SOURCE_REMOVE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nmcs_wait_for_objects_iterate_until_done:
|
|
Packit |
5756e2 |
* @context: the #GMainContext to iterate.
|
|
Packit |
5756e2 |
* @timeout_msec: timeout or -1 for no timeout.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Iterates the provided @context until all objects that we wait for
|
|
Packit |
5756e2 |
* are destroyed.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* The purpose of this is to cleanup all objects that we have on exit. That
|
|
Packit |
5756e2 |
* is especially because objects have asynchronous operations pending that
|
|
Packit |
5756e2 |
* should be cancelled and properly completed during exit.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: %FALSE on timeout or %TRUE if all objects destroyed before timeout.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nmcs_wait_for_objects_iterate_until_done(GMainContext *context, int timeout_msec)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_gmainloop GMainLoop *loop = g_main_loop_new(context, FALSE);
|
|
Packit Service |
a1bd4f |
nm_auto_destroy_and_unref_gsource GSource *timeout_source = NULL;
|
|
Packit Service |
a1bd4f |
WaitForObjectsData data;
|
|
Packit Service |
a1bd4f |
gboolean has_more_objects;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
G_LOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
if (!_wait_for_objects_list) {
|
|
Packit Service |
a1bd4f |
G_UNLOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
_wait_for_objects_iterate_loops = g_slist_prepend(_wait_for_objects_iterate_loops, loop);
|
|
Packit Service |
a1bd4f |
G_UNLOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
data = (WaitForObjectsData){
|
|
Packit Service |
a1bd4f |
.loop = loop,
|
|
Packit Service |
a1bd4f |
.got_timeout = FALSE,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (timeout_msec >= 0) {
|
|
Packit Service |
a1bd4f |
timeout_source = nm_g_source_attach(
|
|
Packit Service |
a1bd4f |
nm_g_timeout_source_new(timeout_msec,
|
|
Packit Service |
a1bd4f |
G_PRIORITY_DEFAULT,
|
|
Packit Service |
a1bd4f |
_wait_for_objects_iterate_until_done_timeout_cb,
|
|
Packit Service |
a1bd4f |
&data,
|
|
Packit Service |
a1bd4f |
NULL),
|
|
Packit Service |
a1bd4f |
context);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
has_more_objects = TRUE;
|
|
Packit Service |
a1bd4f |
while (has_more_objects && !data.got_timeout) {
|
|
Packit Service |
a1bd4f |
nm_auto_destroy_and_unref_gsource GSource *idle_source = NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
idle_source =
|
|
Packit Service |
a1bd4f |
nm_g_source_attach(nm_g_idle_source_new(G_PRIORITY_DEFAULT,
|
|
Packit Service |
a1bd4f |
_wait_for_objects_iterate_until_done_idle_cb,
|
|
Packit Service |
a1bd4f |
&data,
|
|
Packit Service |
a1bd4f |
NULL),
|
|
Packit Service |
a1bd4f |
context);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_main_loop_run(loop);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
G_LOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
has_more_objects = (!!_wait_for_objects_list);
|
|
Packit Service |
a1bd4f |
if (data.got_timeout || !has_more_objects)
|
|
Packit Service |
a1bd4f |
_wait_for_objects_iterate_loops = g_slist_remove(_wait_for_objects_iterate_loops, loop);
|
|
Packit Service |
a1bd4f |
G_UNLOCK(_wait_for_objects_lock);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return !data.got_timeout;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
typedef struct {
|
|
Packit Service |
a1bd4f |
GTask * task;
|
|
Packit Service |
a1bd4f |
GSource * source_timeout;
|
|
Packit Service |
a1bd4f |
GSource * source_next_poll;
|
|
Packit Service |
a1bd4f |
GMainContext * context;
|
|
Packit Service |
a1bd4f |
GCancellable * internal_cancellable;
|
|
Packit Service |
a1bd4f |
NMCSUtilsPollProbeStartFcn probe_start_fcn;
|
|
Packit Service |
a1bd4f |
NMCSUtilsPollProbeFinishFcn probe_finish_fcn;
|
|
Packit Service |
a1bd4f |
gpointer probe_user_data;
|
|
Packit Service |
a1bd4f |
gulong cancellable_id;
|
|
Packit Service |
a1bd4f |
gint64 last_poll_start_ms;
|
|
Packit Service |
a1bd4f |
int sleep_timeout_ms;
|
|
Packit Service |
a1bd4f |
int ratelimit_timeout_ms;
|
|
Packit Service |
a1bd4f |
bool completed : 1;
|
|
Packit |
5756e2 |
} PollTaskData;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
_poll_task_data_free(gpointer data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
PollTaskData *poll_task_data = data;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
nm_assert(G_IS_TASK(poll_task_data->task));
|
|
Packit Service |
a1bd4f |
nm_assert(!poll_task_data->source_next_poll);
|
|
Packit Service |
a1bd4f |
nm_assert(!poll_task_data->source_timeout);
|
|
Packit Service |
a1bd4f |
nm_assert(poll_task_data->cancellable_id == 0);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_main_context_unref(poll_task_data->context);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
nm_g_slice_free(poll_task_data);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
_poll_return(PollTaskData *poll_task_data, GError *error_take)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&poll_task_data->source_next_poll);
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&poll_task_data->source_timeout);
|
|
Packit Service |
a1bd4f |
nm_clear_g_cancellable_disconnect(g_task_get_cancellable(poll_task_data->task),
|
|
Packit Service |
a1bd4f |
&poll_task_data->cancellable_id);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
nm_clear_g_cancellable(&poll_task_data->internal_cancellable);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (error_take)
|
|
Packit Service |
a1bd4f |
g_task_return_error(poll_task_data->task, g_steal_pointer(&error_take));
|
|
Packit Service |
a1bd4f |
else
|
|
Packit Service |
a1bd4f |
g_task_return_boolean(poll_task_data->task, TRUE);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_object_unref(poll_task_data->task);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
static gboolean _poll_start_cb(gpointer user_data);
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
_poll_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
PollTaskData * poll_task_data = user_data;
|
|
Packit Service |
a1bd4f |
_nm_unused gs_unref_object GTask *task =
|
|
Packit Service |
a1bd4f |
poll_task_data->task; /* balance ref from _poll_start_cb() */
|
|
Packit Service |
a1bd4f |
gs_free_error GError *error = NULL;
|
|
Packit Service |
a1bd4f |
gint64 now_ms;
|
|
Packit Service |
a1bd4f |
gint64 wait_ms;
|
|
Packit Service |
a1bd4f |
gboolean is_finished;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
is_finished =
|
|
Packit Service |
a1bd4f |
poll_task_data->probe_finish_fcn(source, result, poll_task_data->probe_user_data, &error);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (nm_utils_error_is_cancelled(error)) {
|
|
Packit Service |
a1bd4f |
/* we already handle this differently. Nothing to do. */
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (error || is_finished) {
|
|
Packit Service |
a1bd4f |
_poll_return(poll_task_data, g_steal_pointer(&error));
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
now_ms = nm_utils_get_monotonic_timestamp_msec();
|
|
Packit Service |
a1bd4f |
if (poll_task_data->ratelimit_timeout_ms > 0)
|
|
Packit Service |
a1bd4f |
wait_ms =
|
|
Packit Service |
a1bd4f |
(poll_task_data->last_poll_start_ms + poll_task_data->ratelimit_timeout_ms) - now_ms;
|
|
Packit Service |
a1bd4f |
else
|
|
Packit Service |
a1bd4f |
wait_ms = 0;
|
|
Packit Service |
a1bd4f |
if (poll_task_data->sleep_timeout_ms > 0)
|
|
Packit Service |
a1bd4f |
wait_ms = MAX(wait_ms, poll_task_data->sleep_timeout_ms);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
poll_task_data->source_next_poll =
|
|
Packit Service |
a1bd4f |
nm_g_source_attach(nm_g_timeout_source_new(MAX(1, wait_ms),
|
|
Packit Service |
a1bd4f |
G_PRIORITY_DEFAULT,
|
|
Packit Service |
a1bd4f |
_poll_start_cb,
|
|
Packit Service |
a1bd4f |
poll_task_data,
|
|
Packit Service |
a1bd4f |
NULL),
|
|
Packit Service |
a1bd4f |
poll_task_data->context);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
_poll_start_cb(gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
PollTaskData *poll_task_data = user_data;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
nm_clear_g_source_inst(&poll_task_data->source_next_poll);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
poll_task_data->last_poll_start_ms = nm_utils_get_monotonic_timestamp_msec();
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_object_ref(poll_task_data->task); /* balanced by _poll_done_cb() */
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
poll_task_data->probe_start_fcn(poll_task_data->internal_cancellable,
|
|
Packit Service |
a1bd4f |
poll_task_data->probe_user_data,
|
|
Packit Service |
a1bd4f |
_poll_done_cb,
|
|
Packit Service |
a1bd4f |
poll_task_data);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
return G_SOURCE_CONTINUE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
_poll_timeout_cb(gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
PollTaskData *poll_task_data = user_data;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
_poll_return(poll_task_data, nm_utils_error_new(NM_UTILS_ERROR_UNKNOWN, "timeout expired"));
|
|
Packit Service |
a1bd4f |
return G_SOURCE_CONTINUE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
_poll_cancelled_cb(GObject *object, gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
PollTaskData *poll_task_data = user_data;
|
|
Packit Service |
a1bd4f |
GError * error = NULL;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
nm_clear_g_signal_handler(g_task_get_cancellable(poll_task_data->task),
|
|
Packit Service |
a1bd4f |
&poll_task_data->cancellable_id);
|
|
Packit Service |
a1bd4f |
nm_utils_error_set_cancelled(&error, FALSE, NULL);
|
|
Packit Service |
a1bd4f |
_poll_return(poll_task_data, error);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nmcs_utils_poll:
|
|
Packit |
5756e2 |
* @poll_timeout_ms: if >= 0, then this is the overall timeout for how long we poll.
|
|
Packit |
5756e2 |
* When this timeout expires, the request completes with failure (and error set).
|
|
Packit |
5756e2 |
* @ratelimit_timeout_ms: if > 0, we ratelimit the starts from one prope_start_fcn
|
|
Packit |
5756e2 |
* call to the next.
|
|
Packit |
5756e2 |
* @sleep_timeout_ms: if > 0, then we wait after a probe finished this timeout
|
|
Packit |
5756e2 |
* before the next. Together with @ratelimit_timeout_ms this determines how
|
|
Packit |
5756e2 |
* frequently we probe.
|
|
Packit |
5756e2 |
* @probe_start_fcn: used to start a (asynchronous) probe. A probe must be completed
|
|
Packit |
5756e2 |
* by calling the provided callback. While a probe is in progress, we will not
|
|
Packit |
5756e2 |
* start another. This function is already invoked the first time synchronously,
|
|
Packit |
5756e2 |
* during nmcs_utils_poll().
|
|
Packit |
5756e2 |
* @probe_finish_fcn: will be called from the callback of @probe_start_fcn. If the
|
|
Packit |
5756e2 |
* function returns %TRUE (polling done) or an error, polling stops. Otherwise,
|
|
Packit |
5756e2 |
* another poll will be started.
|
|
Packit |
5756e2 |
* @probe_user_data: user_data for the probe functions.
|
|
Packit |
5756e2 |
* @cancellable: cancellable for polling.
|
|
Packit |
5756e2 |
* @callback: when polling completes.
|
|
Packit |
5756e2 |
* @user_data: for @callback.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* This uses the current g_main_context_get_thread_default() for scheduling
|
|
Packit |
5756e2 |
* actions.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
void
|
|
Packit Service |
a1bd4f |
nmcs_utils_poll(int poll_timeout_ms,
|
|
Packit Service |
a1bd4f |
int ratelimit_timeout_ms,
|
|
Packit Service |
a1bd4f |
int sleep_timeout_ms,
|
|
Packit Service |
a1bd4f |
NMCSUtilsPollProbeStartFcn probe_start_fcn,
|
|
Packit Service |
a1bd4f |
NMCSUtilsPollProbeFinishFcn probe_finish_fcn,
|
|
Packit Service |
a1bd4f |
gpointer probe_user_data,
|
|
Packit Service |
a1bd4f |
GCancellable * cancellable,
|
|
Packit Service |
a1bd4f |
GAsyncReadyCallback callback,
|
|
Packit Service |
a1bd4f |
gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
PollTaskData *poll_task_data;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
poll_task_data = g_slice_new(PollTaskData);
|
|
Packit Service |
a1bd4f |
*poll_task_data = (PollTaskData){
|
|
Packit Service |
a1bd4f |
.task = nm_g_task_new(NULL, cancellable, nmcs_utils_poll, callback, user_data),
|
|
Packit Service |
a1bd4f |
.probe_start_fcn = probe_start_fcn,
|
|
Packit Service |
a1bd4f |
.probe_finish_fcn = probe_finish_fcn,
|
|
Packit Service |
a1bd4f |
.probe_user_data = probe_user_data,
|
|
Packit Service |
a1bd4f |
.completed = FALSE,
|
|
Packit Service |
a1bd4f |
.context = g_main_context_ref_thread_default(),
|
|
Packit Service |
a1bd4f |
.sleep_timeout_ms = sleep_timeout_ms,
|
|
Packit Service |
a1bd4f |
.ratelimit_timeout_ms = ratelimit_timeout_ms,
|
|
Packit Service |
a1bd4f |
.internal_cancellable = g_cancellable_new(),
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nmcs_wait_for_objects_register(poll_task_data->task);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_task_set_task_data(poll_task_data->task, poll_task_data, _poll_task_data_free);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (poll_timeout_ms >= 0) {
|
|
Packit Service |
a1bd4f |
poll_task_data->source_timeout =
|
|
Packit Service |
a1bd4f |
nm_g_source_attach(nm_g_timeout_source_new(poll_timeout_ms,
|
|
Packit Service |
a1bd4f |
G_PRIORITY_DEFAULT,
|
|
Packit Service |
a1bd4f |
_poll_timeout_cb,
|
|
Packit Service |
a1bd4f |
poll_task_data,
|
|
Packit Service |
a1bd4f |
NULL),
|
|
Packit Service |
a1bd4f |
poll_task_data->context);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
poll_task_data->source_next_poll = nm_g_source_attach(
|
|
Packit Service |
a1bd4f |
nm_g_idle_source_new(G_PRIORITY_DEFAULT, _poll_start_cb, poll_task_data, NULL),
|
|
Packit Service |
a1bd4f |
poll_task_data->context);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (cancellable) {
|
|
Packit Service |
a1bd4f |
gulong signal_id;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
signal_id = g_cancellable_connect(cancellable,
|
|
Packit Service |
a1bd4f |
G_CALLBACK(_poll_cancelled_cb),
|
|
Packit Service |
a1bd4f |
poll_task_data,
|
|
Packit Service |
a1bd4f |
NULL);
|
|
Packit Service |
a1bd4f |
if (signal_id == 0) {
|
|
Packit Service |
a1bd4f |
/* the request is already cancelled. Return. */
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
poll_task_data->cancellable_id = signal_id;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nmcs_utils_poll_finish:
|
|
Packit |
5756e2 |
* @result: the GAsyncResult from the GAsyncReadyCallback callback.
|
|
Packit |
5756e2 |
* @probe_user_data: the user data provided to nmcs_utils_poll().
|
|
Packit |
5756e2 |
* @error: the failure code.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: %TRUE if the polling completed with success. In that case,
|
|
Packit |
5756e2 |
* the error won't be set.
|
|
Packit |
5756e2 |
* If the request was cancelled, this is indicated by @error and
|
|
Packit |
5756e2 |
* %FALSE will be returned.
|
|
Packit |
5756e2 |
* If the probe returned a failure, this returns %FALSE and the error
|
|
Packit |
5756e2 |
* provided by @probe_finish_fcn.
|
|
Packit |
5756e2 |
* If the request times out, this returns %FALSE with error set.
|
|
Packit |
5756e2 |
* Error is always set if (and only if) the function returns %FALSE.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nmcs_utils_poll_finish(GAsyncResult *result, gpointer *probe_user_data, GError **error)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
GTask * task;
|
|
Packit Service |
a1bd4f |
PollTaskData *poll_task_data;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(nm_g_task_is_valid(result, NULL, nmcs_utils_poll), FALSE);
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(!error || !*error, FALSE);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
task = G_TASK(result);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (probe_user_data) {
|
|
Packit Service |
a1bd4f |
poll_task_data = g_task_get_task_data(task);
|
|
Packit Service |
a1bd4f |
NM_SET_OUT(probe_user_data, poll_task_data->probe_user_data);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
return g_task_propagate_boolean(task, error);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
char *
|
|
Packit Service |
a1bd4f |
nmcs_utils_hwaddr_normalize(const char *hwaddr, gssize len)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gs_free char *hwaddr_clone = NULL;
|
|
Packit Service |
a1bd4f |
guint8 buf[ETH_ALEN];
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(len >= -1);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (len < 0) {
|
|
Packit Service |
a1bd4f |
if (!hwaddr)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
if (len == 0)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
nm_assert(hwaddr);
|
|
Packit Service |
a1bd4f |
hwaddr = nm_strndup_a(300, hwaddr, len, &hwaddr_clone);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
/* we cannot use _nm_utils_hwaddr_aton() because that requires a delimiter.
|
|
Packit Service |
a1bd4f |
* Azure exposes MAC addresses without delimiter, so accept that too. */
|
|
Packit Service |
a1bd4f |
if (!nm_utils_hexstr2bin_full(hwaddr,
|
|
Packit Service |
a1bd4f |
FALSE,
|
|
Packit Service |
a1bd4f |
FALSE,
|
|
Packit Service |
a1bd4f |
FALSE,
|
|
Packit Service |
a1bd4f |
":-",
|
|
Packit Service |
a1bd4f |
sizeof(buf),
|
|
Packit Service |
a1bd4f |
buf,
|
|
Packit Service |
a1bd4f |
sizeof(buf),
|
|
Packit Service |
a1bd4f |
NULL))
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return nm_utils_hwaddr_ntoa(buf, sizeof(buf));
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
const char *
|
|
Packit Service |
a1bd4f |
nmcs_utils_parse_memmem(GBytes *mem, const char *needle)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
const char *mem_data;
|
|
Packit Service |
a1bd4f |
gsize mem_size;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(mem, NULL);
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(needle, NULL);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
mem_data = g_bytes_get_data(mem, &mem_size);
|
|
Packit Service |
a1bd4f |
return memmem(mem_data, mem_size, needle, strlen(needle));
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
const char *
|
|
Packit Service |
a1bd4f |
nmcs_utils_parse_get_full_line(GBytes *mem, const char *needle)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
const char *mem_data;
|
|
Packit Service |
a1bd4f |
gsize mem_size;
|
|
Packit Service |
a1bd4f |
gsize c;
|
|
Packit Service |
a1bd4f |
gsize l;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
const char *line;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
line = nmcs_utils_parse_memmem(mem, needle);
|
|
Packit Service |
a1bd4f |
if (!line)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
mem_data = g_bytes_get_data(mem, &mem_size);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (line != mem_data && line[-1] != '\n') {
|
|
Packit Service |
a1bd4f |
/* the line must be preceeded either by the begin of the data or
|
|
Packit Service |
a1bd4f |
* by a newline. */
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
c = mem_size - (line - mem_data);
|
|
Packit Service |
a1bd4f |
l = strlen(needle);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (c != l && line[l] != '\n') {
|
|
Packit Service |
a1bd4f |
/* the end of the needle must be either a newline or the end of the buffer. */
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
return line;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
char *
|
|
Packit Service |
a1bd4f |
nmcs_utils_uri_build_concat_v(const char *base, const char **components, gsize n_components)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMStrBuf strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_assert(base);
|
|
Packit Service |
a1bd4f |
nm_assert(base[0]);
|
|
Packit Service |
a1bd4f |
nm_assert(!NM_STR_HAS_SUFFIX(base, "/"));
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_str_buf_append(&strbuf, base);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (n_components > 0 && components[0] && components[0][0] == '/') {
|
|
Packit Service |
a1bd4f |
/* the first component starts with a slash. We allow that, and don't add a duplicate
|
|
Packit Service |
a1bd4f |
* slash. Otherwise, we add a separator after base.
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* We only do that for the first component. */
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
nm_str_buf_append_c(&strbuf, '/');
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
while (n_components > 0) {
|
|
Packit Service |
a1bd4f |
if (!components[0]) {
|
|
Packit Service |
a1bd4f |
/* we allow NULL, to indicate nothing to append */
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
nm_str_buf_append(&strbuf, components[0]);
|
|
Packit Service |
a1bd4f |
components++;
|
|
Packit Service |
a1bd4f |
n_components--;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return nm_str_buf_finalize(&strbuf, NULL);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nmcs_setting_ip_replace_ipv4_addresses(NMSettingIPConfig *s_ip,
|
|
Packit Service |
a1bd4f |
NMIPAddress ** entries_arr,
|
|
Packit Service |
a1bd4f |
guint entries_len)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gboolean any_changes = FALSE;
|
|
Packit Service |
a1bd4f |
guint i_next;
|
|
Packit Service |
a1bd4f |
guint num;
|
|
Packit Service |
a1bd4f |
guint i;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
num = nm_setting_ip_config_get_num_addresses(s_ip);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
i_next = 0;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (i = 0; i < entries_len; i++) {
|
|
Packit Service |
a1bd4f |
NMIPAddress *entry = entries_arr[i];
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!any_changes) {
|
|
Packit Service |
a1bd4f |
if (i_next < num) {
|
|
Packit Service |
a1bd4f |
if (nm_ip_address_cmp_full(entry,
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_get_address(s_ip, i_next),
|
|
Packit Service |
a1bd4f |
NM_IP_ADDRESS_CMP_FLAGS_WITH_ATTRS)
|
|
Packit Service |
a1bd4f |
== 0) {
|
|
Packit Service |
a1bd4f |
i_next++;
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
while (i_next < num)
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_remove_address(s_ip, --num);
|
|
Packit Service |
a1bd4f |
any_changes = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!nm_setting_ip_config_add_address(s_ip, entry))
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
i_next++;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (any_changes) {
|
|
Packit Service |
a1bd4f |
while (i_next < num) {
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_remove_address(s_ip, --num);
|
|
Packit Service |
a1bd4f |
any_changes = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return any_changes;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nmcs_setting_ip_replace_ipv4_routes(NMSettingIPConfig *s_ip,
|
|
Packit Service |
a1bd4f |
NMIPRoute ** entries_arr,
|
|
Packit Service |
a1bd4f |
guint entries_len)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gboolean any_changes = FALSE;
|
|
Packit Service |
a1bd4f |
guint i_next;
|
|
Packit Service |
a1bd4f |
guint num;
|
|
Packit Service |
a1bd4f |
guint i;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
num = nm_setting_ip_config_get_num_routes(s_ip);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
i_next = 0;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (i = 0; i < entries_len; i++) {
|
|
Packit Service |
a1bd4f |
NMIPRoute *entry = entries_arr[i];
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!any_changes) {
|
|
Packit Service |
a1bd4f |
if (i_next < num) {
|
|
Packit Service |
a1bd4f |
if (nm_ip_route_equal_full(entry,
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_get_route(s_ip, i_next),
|
|
Packit Service |
a1bd4f |
NM_IP_ROUTE_EQUAL_CMP_FLAGS_WITH_ATTRS)) {
|
|
Packit Service |
a1bd4f |
i_next++;
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
while (i_next < num)
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_remove_route(s_ip, --num);
|
|
Packit Service |
a1bd4f |
any_changes = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!nm_setting_ip_config_add_route(s_ip, entry))
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
i_next++;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (!any_changes) {
|
|
Packit Service |
a1bd4f |
while (i_next < num) {
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_remove_route(s_ip, --num);
|
|
Packit Service |
a1bd4f |
any_changes = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return any_changes;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nmcs_setting_ip_replace_ipv4_rules(NMSettingIPConfig *s_ip,
|
|
Packit Service |
a1bd4f |
NMIPRoutingRule ** entries_arr,
|
|
Packit Service |
a1bd4f |
guint entries_len)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gboolean any_changes = FALSE;
|
|
Packit Service |
a1bd4f |
guint i_next;
|
|
Packit Service |
a1bd4f |
guint num;
|
|
Packit Service |
a1bd4f |
guint i;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
num = nm_setting_ip_config_get_num_routing_rules(s_ip);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
i_next = 0;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
for (i = 0; i < entries_len; i++) {
|
|
Packit Service |
a1bd4f |
NMIPRoutingRule *entry = entries_arr[i];
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!any_changes) {
|
|
Packit Service |
a1bd4f |
if (i_next < num) {
|
|
Packit Service |
a1bd4f |
if (nm_ip_routing_rule_cmp(entry,
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_get_routing_rule(s_ip, i_next))
|
|
Packit Service |
a1bd4f |
== 0) {
|
|
Packit Service |
a1bd4f |
i_next++;
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
while (i_next < num)
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_remove_routing_rule(s_ip, --num);
|
|
Packit Service |
a1bd4f |
any_changes = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_add_routing_rule(s_ip, entry);
|
|
Packit Service |
a1bd4f |
i_next++;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (!any_changes) {
|
|
Packit Service |
a1bd4f |
while (i_next < num) {
|
|
Packit Service |
a1bd4f |
nm_setting_ip_config_remove_routing_rule(s_ip, --num);
|
|
Packit Service |
a1bd4f |
any_changes = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return any_changes;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
typedef struct {
|
|
Packit Service |
a1bd4f |
GMainLoop * main_loop;
|
|
Packit Service |
a1bd4f |
NMConnection *connection;
|
|
Packit Service |
a1bd4f |
GError * error;
|
|
Packit Service |
a1bd4f |
guint64 version_id;
|
|
Packit |
5756e2 |
} DeviceGetAppliedConnectionData;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
_nmcs_device_get_applied_connection_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
DeviceGetAppliedConnectionData *data = user_data;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
data->connection = nm_device_get_applied_connection_finish(NM_DEVICE(source),
|
|
Packit Service |
a1bd4f |
result,
|
|
Packit Service |
a1bd4f |
&data->version_id,
|
|
Packit Service |
a1bd4f |
&data->error);
|
|
Packit Service |
a1bd4f |
g_main_loop_quit(data->main_loop);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
NMConnection *
|
|
Packit Service |
a1bd4f |
nmcs_device_get_applied_connection(NMDevice * device,
|
|
Packit Service |
a1bd4f |
GCancellable *cancellable,
|
|
Packit Service |
a1bd4f |
guint64 * version_id,
|
|
Packit Service |
a1bd4f |
GError ** error)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(NULL, FALSE);
|
|
Packit Service |
a1bd4f |
DeviceGetAppliedConnectionData data = {
|
|
Packit Service |
a1bd4f |
.main_loop = main_loop,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_device_get_applied_connection_async(device,
|
|
Packit Service |
a1bd4f |
0,
|
|
Packit Service |
a1bd4f |
cancellable,
|
|
Packit Service |
a1bd4f |
_nmcs_device_get_applied_connection_cb,
|
|
Packit Service |
a1bd4f |
&data);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_main_loop_run(main_loop);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (data.error)
|
|
Packit Service |
a1bd4f |
g_propagate_error(error, data.error);
|
|
Packit Service |
a1bd4f |
NM_SET_OUT(version_id, data.version_id);
|
|
Packit Service |
a1bd4f |
return data.connection;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
typedef struct {
|
|
Packit Service |
a1bd4f |
GMainLoop *main_loop;
|
|
Packit Service |
a1bd4f |
GError * error;
|
|
Packit |
5756e2 |
} DeviceReapplyData;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
_nmcs_device_reapply_cb(GObject *source, GAsyncResult *result, gpointer user_data)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
DeviceReapplyData *data = user_data;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
nm_device_reapply_finish(NM_DEVICE(source), result, &data->error);
|
|
Packit Service |
a1bd4f |
g_main_loop_quit(data->main_loop);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nmcs_device_reapply(NMDevice * device,
|
|
Packit Service |
a1bd4f |
GCancellable *sigterm_cancellable,
|
|
Packit Service |
a1bd4f |
NMConnection *connection,
|
|
Packit Service |
a1bd4f |
guint64 version_id,
|
|
Packit Service |
a1bd4f |
gboolean * out_version_id_changed,
|
|
Packit Service |
a1bd4f |
GError ** error)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
nm_auto_unref_gmainloop GMainLoop *main_loop = g_main_loop_new(NULL, FALSE);
|
|
Packit Service |
a1bd4f |
DeviceReapplyData data = {
|
|
Packit Service |
a1bd4f |
.main_loop = main_loop,
|
|
Packit Service |
a1bd4f |
};
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_device_reapply_async(device,
|
|
Packit Service |
a1bd4f |
connection,
|
|
Packit Service |
a1bd4f |
version_id,
|
|
Packit Service |
a1bd4f |
0,
|
|
Packit Service |
a1bd4f |
sigterm_cancellable,
|
|
Packit Service |
a1bd4f |
_nmcs_device_reapply_cb,
|
|
Packit Service |
a1bd4f |
&data);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_main_loop_run(main_loop);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (data.error) {
|
|
Packit Service |
a1bd4f |
NM_SET_OUT(
|
|
Packit Service |
a1bd4f |
out_version_id_changed,
|
|
Packit Service |
a1bd4f |
g_error_matches(data.error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_VERSION_ID_MISMATCH));
|
|
Packit Service |
a1bd4f |
g_propagate_error(error, data.error);
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
NM_SET_OUT(out_version_id_changed, FALSE);
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit |
5756e2 |
}
|