summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-05-27 12:44:25 +0200
committerThomas Haller <thaller@redhat.com>2019-05-27 12:44:25 +0200
commit51793569e18e7b7b71cdff92d8fe513f973f6e78 (patch)
tree8c1c5eb7807b1fade8432103d6cde81f1b40c382
parent8f1b542bd7406e78bb3f56bdbeeb9d3e889c695b (diff)
parent7ea76c07e52ed6c5f4d78e52fd03e1e7e9b3da78 (diff)
downloadNetworkManager-51793569e18e7b7b71cdff92d8fe513f973f6e78.tar.gz
dispatcher: merge branch 'th/dispatcher-cleanup'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/162
-rw-r--r--Makefile.am49
-rw-r--r--data/NetworkManager-dispatcher.service.in6
-rw-r--r--dispatcher/meson.build2
-rw-r--r--dispatcher/nm-dispatcher.c630
-rw-r--r--dispatcher/tests/meson.build2
-rw-r--r--dispatcher/tests/test-dispatcher-envp.c15
-rw-r--r--shared/nm-glib-aux/nm-macros-internal.h2
-rw-r--r--src/devices/nm-device.c40
-rw-r--r--src/main.c2
-rw-r--r--src/nm-dispatcher.c467
-rw-r--r--src/nm-dispatcher.h16
-rw-r--r--src/vpn/nm-vpn-connection.c22
12 files changed, 726 insertions, 527 deletions
diff --git a/Makefile.am b/Makefile.am
index cf2ee34a1f..c830919df7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3885,6 +3885,25 @@ EXTRA_DIST += \
# dispatcher
###############################################################################
+dispatcher_nmdbus_dispatcher_sources = \
+ dispatcher/nmdbus-dispatcher.h \
+ dispatcher/nmdbus-dispatcher.c \
+ $(NULL)
+
+dispatcher/nmdbus-dispatcher.h: dispatcher/nm-dispatcher.xml
+ @$(MKDIR_P) dispatcher/
+ $(AM_V_GEN) gdbus-codegen \
+ --generate-c-code $(basename $@) \
+ --c-namespace NMDBus \
+ --interface-prefix org.freedesktop \
+ $<
+
+dispatcher/nmdbus-dispatcher.c: dispatcher/nmdbus-dispatcher.h
+
+CLEANFILES += $(dispatcher_nmdbus_dispatcher_sources)
+
+###############################################################################
+
libexec_PROGRAMS += dispatcher/nm-dispatcher
noinst_LTLIBRARIES += \
@@ -3905,25 +3924,6 @@ dispatcher_cppflags = \
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT \
$(NULL)
-
-dispatcher_nmdbus_dispatcher_sources = \
- dispatcher/nmdbus-dispatcher.h \
- dispatcher/nmdbus-dispatcher.c
-
-dispatcher/nmdbus-dispatcher.h: dispatcher/nm-dispatcher.xml
- @$(MKDIR_P) dispatcher/
- $(AM_V_GEN) gdbus-codegen \
- --generate-c-code $(basename $@) \
- --c-namespace NMDBus \
- --interface-prefix org.freedesktop \
- $<
-
-dispatcher/nmdbus-dispatcher.c: dispatcher/nmdbus-dispatcher.h
-
-$(dispatcher_nm_dispatcher_OBJECTS): $(dispatcher_nmdbus_dispatcher_sources)
-
-CLEANFILES += $(dispatcher_nmdbus_dispatcher_sources)
-
dispatcher_libnm_dispatcher_core_la_SOURCES = \
dispatcher/nm-dispatcher-utils.c \
dispatcher/nm-dispatcher-utils.h \
@@ -3939,8 +3939,6 @@ dispatcher_nm_dispatcher_SOURCES = \
dispatcher/nm-dispatcher.c \
$(NULL)
-nodist_dispatcher_nm_dispatcher_SOURCES = $(dispatcher_nmdbus_dispatcher_sources)
-
dispatcher_nm_dispatcher_CPPFLAGS = $(dispatcher_cppflags)
dispatcher_nm_dispatcher_LDFLAGS = \
@@ -3998,12 +3996,21 @@ dispatcher_tests_test_dispatcher_envp_CPPFLAGS = \
-I$(srcdir)/libnm \
-I$(builddir)/libnm \
-I$(srcdir)/dispatcher \
+ -I$(builddir)/dispatcher \
-DNETWORKMANAGER_COMPILATION_TEST \
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT \
$(GLIB_CFLAGS) \
$(SANITIZER_EXEC_CFLAGS) \
$(NULL)
+dispatcher_tests_test_dispatcher_envp_SOURCES = \
+ dispatcher/tests/test-dispatcher-envp.c \
+ $(NULL)
+
+nodist_dispatcher_tests_test_dispatcher_envp_SOURCES = $(dispatcher_nmdbus_dispatcher_sources)
+
+$(dispatcher_tests_test_dispatcher_envp_OBJECTS): $(dispatcher_nmdbus_dispatcher_sources)
+
dispatcher_tests_test_dispatcher_envp_LDFLAGS = \
$(SANITIZER_EXEC_LDFLAGS) \
$(NULL)
diff --git a/data/NetworkManager-dispatcher.service.in b/data/NetworkManager-dispatcher.service.in
index c450478bac..80dc2a1b8d 100644
--- a/data/NetworkManager-dispatcher.service.in
+++ b/data/NetworkManager-dispatcher.service.in
@@ -1,6 +1,12 @@
[Unit]
Description=Network Manager Script Dispatcher Service
+# Order the dispatcher before NetworkManager. While dispatcher
+# is D-Bus activate (and not intended to be explicitly wanted by
+# another service/target), the ordering dependency matters during
+# shutdown. We want first NetworkManager to be stopped.
+Before=NetworkManager.service
+
[Service]
Type=dbus
BusName=org.freedesktop.nm_dispatcher
diff --git a/dispatcher/meson.build b/dispatcher/meson.build
index 7bd41935c5..da9ac7f292 100644
--- a/dispatcher/meson.build
+++ b/dispatcher/meson.build
@@ -44,7 +44,7 @@ libnm_dispatcher_core = static_library(
sources = files('nm-dispatcher.c')
-sources += gnome.gdbus_codegen(
+nmdbus_dispatcher_sources = gnome.gdbus_codegen(
'nmdbus-dispatcher',
name + '.xml',
interface_prefix: 'org.freedesktop',
diff --git a/dispatcher/nm-dispatcher.c b/dispatcher/nm-dispatcher.c
index 231a3f9a83..a803c9759d 100644
--- a/dispatcher/nm-dispatcher.c
+++ b/dispatcher/nm-dispatcher.c
@@ -34,74 +34,24 @@
#include "nm-libnm-core-aux/nm-dispatcher-api.h"
#include "nm-dispatcher-utils.h"
-#include "nmdbus-dispatcher.h"
-
-static GMainLoop *loop = NULL;
-static gboolean debug = FALSE;
-static gboolean persist = FALSE;
-static guint quit_id;
-static guint request_id_counter = 0;
+/*****************************************************************************/
typedef struct Request Request;
-typedef struct {
- GObject parent;
-
- /* Private data */
- NMDBusDispatcher *dbus_dispatcher;
+static struct {
+ GDBusConnection *dbus_connection;
+ GMainLoop *loop;
+ gboolean debug;
+ gboolean persist;
+ guint quit_id;
+ guint request_id_counter;
+ gboolean ever_acquired_name;
+ bool exit_with_failure;
Request *current_request;
GQueue *requests_waiting;
int num_requests_pending;
-} Handler;
-
-typedef struct {
- GObjectClass parent;
-} HandlerClass;
-
-GType handler_get_type (void);
-
-#define HANDLER_TYPE (handler_get_type ())
-#define HANDLER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), HANDLER_TYPE, Handler))
-#define HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), HANDLER_TYPE, HandlerClass))
-
-G_DEFINE_TYPE(Handler, handler, G_TYPE_OBJECT)
-
-static gboolean
-handle_action (NMDBusDispatcher *dbus_dispatcher,
- GDBusMethodInvocation *context,
- const char *str_action,
- GVariant *connection_dict,
- GVariant *connection_props,
- GVariant *device_props,
- GVariant *device_proxy_props,
- GVariant *device_ip4_props,
- GVariant *device_ip6_props,
- GVariant *device_dhcp4_props,
- GVariant *device_dhcp6_props,
- const char *connectivity_state,
- const char *vpn_ip_iface,
- GVariant *vpn_proxy_props,
- GVariant *vpn_ip4_props,
- GVariant *vpn_ip6_props,
- gboolean request_debug,
- gpointer user_data);
-
-static void
-handler_init (Handler *h)
-{
- h->requests_waiting = g_queue_new ();
- h->dbus_dispatcher = nmdbus_dispatcher_skeleton_new ();
- g_signal_connect (h->dbus_dispatcher, "handle-action",
- G_CALLBACK (handle_action), h);
-}
-
-static void
-handler_class_init (HandlerClass *h_class)
-{
-}
-
-static gboolean dispatch_one_script (Request *request);
+} gl;
typedef struct {
Request *request;
@@ -117,8 +67,6 @@ typedef struct {
} ScriptInfo;
struct Request {
- Handler *handler;
-
guint request_id;
GDBusMethodInvocation *context;
@@ -135,52 +83,86 @@ struct Request {
/*****************************************************************************/
-#define __LOG_print(print_cmd, _request, _script, ...) \
+#define __LOG_print(print_cmd, ...) \
G_STMT_START { \
- nm_assert ((_request) && (!(_script) || (_script)->request == (_request))); \
- print_cmd ("req:%u '%s'%s%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
- (_request)->request_id, \
- (_request)->action, \
- (_request)->iface ? " [" : "", \
- (_request)->iface ?: "", \
- (_request)->iface ? "]" : "", \
- (_script) ? ", \"" : "", \
- (_script) ? (_script)->script : "", \
- (_script) ? "\"" : "" \
- _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+ if (FALSE) { \
+ /* g_message() alone does not warn about invalid format. Add a dummy printf() statement to
+ * get a compiler warning about wrong format. */ \
+ printf (__VA_ARGS__); \
+ } \
+ print_cmd (__VA_ARGS__); \
} G_STMT_END
-#define _LOG(_request, _script, log_always, print_cmd, ...) \
+#define __LOG_print_R(print_cmd, _request, ...) \
G_STMT_START { \
- const Request *__request = (_request); \
- const ScriptInfo *__script = (_script); \
+ __LOG_print (print_cmd, \
+ "req:%u '%s'%s%s%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+ (_request)->request_id, \
+ (_request)->action, \
+ (_request)->iface ? " [" : "", \
+ (_request)->iface ?: "", \
+ (_request)->iface ? "]" : "" \
+ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+ } G_STMT_END
+
+#define __LOG_print_S(print_cmd, _request, _script, ...) \
+ G_STMT_START { \
+ __LOG_print_R (print_cmd, \
+ (_request), \
+ "%s%s%s" _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+ (_script) ? ", \"" : "", \
+ (_script) ? (_script)->script : "", \
+ (_script) ? "\"" : "" \
+ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
+ } G_STMT_END
+
+#define _LOG_X_(enabled_cmd, print_cmd, ...) \
+ G_STMT_START { \
+ if (enabled_cmd) \
+ __LOG_print (print_cmd, __VA_ARGS__); \
+ } G_STMT_END
+
+#define _LOG_R_(enabled_cmd, x_request, print_cmd, ...) \
+ G_STMT_START { \
+ const Request *const _request = (x_request); \
\
- if (!__request) \
- __request = __script->request; \
- nm_assert (__request && (!__script || __script->request == __request)); \
- if ((log_always) || _LOG_R_D_enabled (__request)) { \
- if (FALSE) { \
- /* g_message() alone does not warn about invalid format. Add a dummy printf() statement to
- * get a compiler warning about wrong format. */ \
- __LOG_print (printf, __request, __script, __VA_ARGS__); \
- } \
- __LOG_print (print_cmd, __request, __script, __VA_ARGS__); \
- } \
+ nm_assert (_request); \
+ if (enabled_cmd) \
+ __LOG_print_R (print_cmd, _request, ": "__VA_ARGS__); \
} G_STMT_END
-static gboolean
-_LOG_R_D_enabled (const Request *request)
-{
- return request->debug;
-}
+#define _LOG_S_(enabled_cmd, x_script, print_cmd, ...) \
+ G_STMT_START { \
+ const ScriptInfo *const _script = (x_script); \
+ const Request *const _request = _script ? _script->request : NULL; \
+ \
+ nm_assert (_script && _request); \
+ if (enabled_cmd) \
+ __LOG_print_S (print_cmd, _request, _script, ": "__VA_ARGS__); \
+ } G_STMT_END
+
+#define _LOG_X_D_enabled() (gl.debug)
+#define _LOG_X_T_enabled() _LOG_X_D_enabled ()
+
+#define _LOG_R_D_enabled(request) (_NM_ENSURE_TYPE_CONST (Request *, request)->debug)
+#define _LOG_R_T_enabled(request) _LOG_R_D_enabled (request)
+
+#define _LOG_X_T(...) _LOG_X_ (_LOG_X_T_enabled (), g_debug, __VA_ARGS__)
+#define _LOG_X_D(...) _LOG_X_ (_LOG_X_D_enabled (), g_info, __VA_ARGS__)
+#define _LOG_X_I(...) _LOG_X_ (TRUE, g_message, __VA_ARGS__)
+#define _LOG_X_W(...) _LOG_X_ (TRUE, g_warning, __VA_ARGS__)
+
+#define _LOG_R_T(request, ...) _LOG_R_ (_LOG_R_T_enabled (_request), request, g_debug, __VA_ARGS__)
+#define _LOG_R_D(request, ...) _LOG_R_ (_LOG_R_D_enabled (_request), request, g_info, __VA_ARGS__)
+#define _LOG_R_W(request, ...) _LOG_R_ (TRUE, request, g_warning, __VA_ARGS__)
+
+#define _LOG_S_T(script, ...) _LOG_S_ (_LOG_R_T_enabled (_request), script, g_debug, __VA_ARGS__)
+#define _LOG_S_D(script, ...) _LOG_S_ (_LOG_R_D_enabled (_request), script, g_info, __VA_ARGS__)
+#define _LOG_S_W(script, ...) _LOG_S_ (TRUE, script, g_warning, __VA_ARGS__)
-#define _LOG_R_D(_request, ...) _LOG(_request, NULL, FALSE, g_debug, __VA_ARGS__)
-#define _LOG_R_I(_request, ...) _LOG(_request, NULL, TRUE, g_info, __VA_ARGS__)
-#define _LOG_R_W(_request, ...) _LOG(_request, NULL, TRUE, g_warning, __VA_ARGS__)
+/*****************************************************************************/
-#define _LOG_S_D(_script, ...) _LOG(NULL, _script, FALSE, g_debug, __VA_ARGS__)
-#define _LOG_S_I(_script, ...) _LOG(NULL, _script, TRUE, g_info, __VA_ARGS__)
-#define _LOG_S_W(_script, ...) _LOG(NULL, _script, TRUE, g_warning, __VA_ARGS__)
+static gboolean dispatch_one_script (Request *request);
/*****************************************************************************/
@@ -211,23 +193,23 @@ request_free (Request *request)
static gboolean
quit_timeout_cb (gpointer user_data)
{
- g_main_loop_quit (loop);
- return FALSE;
+ gl.quit_id = 0;
+ g_main_loop_quit (gl.loop);
+ return G_SOURCE_REMOVE;
}
static void
quit_timeout_reschedule (void)
{
- if (!persist) {
- nm_clear_g_source (&quit_id);
- quit_id = g_timeout_add_seconds (10, quit_timeout_cb, NULL);
+ if (!gl.persist) {
+ nm_clear_g_source (&gl.quit_id);
+ gl.quit_id = g_timeout_add_seconds (10, quit_timeout_cb, NULL);
}
}
/**
* next_request:
*
- * @h: the handler
* @request: (allow-none): the request to set as next. If %NULL, dequeue the next
* waiting request. Otherwise, try to set the given request.
*
@@ -240,27 +222,27 @@ quit_timeout_reschedule (void)
* a new request as current.
*/
static gboolean
-next_request (Handler *h, Request *request)
+next_request (Request *request)
{
if (request) {
- if (h->current_request) {
- g_queue_push_tail (h->requests_waiting, request);
+ if (gl.current_request) {
+ g_queue_push_tail (gl.requests_waiting, request);
return FALSE;
}
} else {
/* when calling next_request() without explicit @request, we always
* forcefully clear @current_request. That one is certainly
* handled already. */
- h->current_request = NULL;
+ gl.current_request = NULL;
- request = g_queue_pop_head (h->requests_waiting);
+ request = g_queue_pop_head (gl.requests_waiting);
if (!request)
return FALSE;
}
- _LOG_R_I (request, "start running ordered scripts...");
+ _LOG_R_D (request, "start running ordered scripts...");
- h->current_request = request;
+ gl.current_request = request;
return TRUE;
}
@@ -280,7 +262,6 @@ complete_request (Request *request)
GVariantBuilder results;
GVariant *ret;
guint i;
- Handler *handler = request->handler;
nm_assert (request);
@@ -301,16 +282,16 @@ complete_request (Request *request)
ret = g_variant_new ("(a(sus))", &results);
g_dbus_method_invocation_return_value (request->context, ret);
- _LOG_R_D (request, "completed (%u scripts)", request->scripts->len);
+ _LOG_R_T (request, "completed (%u scripts)", request->scripts->len);
- if (handler->current_request == request)
- handler->current_request = NULL;
+ if (gl.current_request == request)
+ gl.current_request = NULL;
request_free (request);
- g_assert_cmpuint (handler->num_requests_pending, >, 0);
- if (--handler->num_requests_pending <= 0) {
- nm_assert (!handler->current_request && !g_queue_peek_head (handler->requests_waiting));
+ g_assert_cmpuint (gl.num_requests_pending, >, 0);
+ if (--gl.num_requests_pending <= 0) {
+ nm_assert (!gl.current_request && !g_queue_peek_head (gl.requests_waiting));
quit_timeout_reschedule ();
}
}
@@ -318,7 +299,6 @@ complete_request (Request *request)
static void
complete_script (ScriptInfo *script)
{
- Handler *handler;
Request *request;
gboolean wait = script->wait;
@@ -331,9 +311,7 @@ complete_script (ScriptInfo *script)
return;
}
- handler = request->handler;
-
- nm_assert (!wait || handler->current_request == request);
+ nm_assert (!wait || gl.current_request == request);
/* Try to complete the request. @request will be possibly free'd,
* making @script and @request a dangling pointer. */
@@ -346,13 +324,13 @@ complete_script (ScriptInfo *script)
* requests. However, if this was the last "no-wait" script and
* there are "wait" scripts ready to run, launch them.
*/
- if ( handler->current_request == request
- && handler->current_request->num_scripts_nowait == 0) {
+ if ( gl.current_request == request
+ && gl.current_request->num_scripts_nowait == 0) {
- if (dispatch_one_script (handler->current_request))
+ if (dispatch_one_script (gl.current_request))
return;
- complete_request (handler->current_request);
+ complete_request (gl.current_request);
} else
return;
} else {
@@ -365,11 +343,11 @@ complete_script (ScriptInfo *script)
* processed because only requests with "wait" scripts can become
* @current_request. As there can only be one "wait" script running
* at any time, it means complete_request() above completed @request. */
- nm_assert (!handler->current_request);
+ nm_assert (!gl.current_request);
}
- while (next_request (handler, NULL)) {
- request = handler->current_request;
+ while (next_request (NULL)) {
+ request = gl.current_request;
if (dispatch_one_script (request))
return;
@@ -418,7 +396,7 @@ script_watch_cb (GPid pid, int status, gpointer user_data)
}
if (script->result == DISPATCH_RESULT_SUCCESS) {
- _LOG_S_D (script, "complete");
+ _LOG_S_T (script, "complete");
} else {
script->result = DISPATCH_RESULT_FAILED;
_LOG_S_W (script, "complete: failed with %s", script->error);
@@ -533,7 +511,7 @@ script_dispatch (ScriptInfo *script)
argv[2] = request->action;
argv[3] = NULL;
- _LOG_S_D (script, "run script%s", script->wait ? "" : " (no-wait)");
+ _LOG_S_T (script, "run script%s", script->wait ? "" : " (no-wait)");
if (g_spawn_async ("/", argv, request->envp, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &script->pid, &error)) {
script->watch_id = g_child_watch_add (script->pid, (GChildWatchFunc) script_watch_cb, script);
@@ -586,7 +564,7 @@ _compare_basenames (gconstpointer a, gconstpointer b)
}
static void
-_find_scripts (GHashTable *scripts, const char *base, const char *subdir)
+_find_scripts (Request *request, GHashTable *scripts, const char *base, const char *subdir)
{
const char *filename;
gs_free char *dirname = NULL;
@@ -596,8 +574,10 @@ _find_scripts (GHashTable *scripts, const char *base, const char *subdir)
dirname = g_build_filename (base, "dispatcher.d", subdir, NULL);
if (!(dir = g_dir_open (dirname, 0, &error))) {
- g_message ("find-scripts: Failed to open dispatcher directory '%s': %s",
- dirname, error->message);
+ if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
+ _LOG_R_W (request, "find-scripts: Failed to open dispatcher directory '%s': %s",
+ dirname, error->message);
+ }
g_error_free (error);
return;
}
@@ -615,26 +595,28 @@ _find_scripts (GHashTable *scripts, const char *base, const char *subdir)
}
static GSList *
-find_scripts (const char *str_action)
+find_scripts (Request *request)
{
gs_unref_hashtable GHashTable *scripts = NULL;
GSList *script_list = NULL;
GHashTableIter iter;
- const char *subdir = NULL;
+ const char *subdir;
char *path;
char *filename;
- if ( strcmp (str_action, NMD_ACTION_PRE_UP) == 0
- || strcmp (str_action, NMD_ACTION_VPN_PRE_UP) == 0)
+ if (NM_IN_STRSET (request->action, NMD_ACTION_PRE_UP,
+ NMD_ACTION_VPN_PRE_UP))
subdir = "pre-up.d";
- else if ( strcmp (str_action, NMD_ACTION_PRE_DOWN) == 0
- || strcmp (str_action, NMD_ACTION_VPN_PRE_DOWN) == 0)
+ else if (NM_IN_STRSET (request->action, NMD_ACTION_PRE_DOWN,
+ NMD_ACTION_VPN_PRE_DOWN))
subdir = "pre-down.d";
+ else
+ subdir = NULL;
scripts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
- _find_scripts (scripts, NMLIBDIR, subdir);
- _find_scripts (scripts, NMCONFDIR, subdir);
+ _find_scripts (request, scripts, NMLIBDIR, subdir);
+ _find_scripts (request, scripts, NMCONFDIR, subdir);
g_hash_table_iter_init (&iter, scripts);
while (g_hash_table_iter_next (&iter, (gpointer *) &filename, (gpointer *) &path)) {
@@ -652,11 +634,11 @@ find_scripts (const char *str_action)
err = stat (path, &st);
if (err)
- g_warning ("find-scripts: Failed to stat '%s': %d", path, err);
+ _LOG_R_W (request, "find-scripts: Failed to stat '%s': %d", path, err);
else if (!S_ISREG (st.st_mode))
; /* silently skip. */
else if (!check_permissions (&st, &err_msg))
- g_warning ("find-scripts: Cannot execute '%s': %s", path, err_msg);
+ _LOG_R_W (request, "find-scripts: Cannot execute '%s': %s", path, err_msg);
else {
/* success */
script_list = g_slist_prepend (script_list, g_strdup (path));
@@ -695,27 +677,25 @@ script_must_wait (const char *path)
return TRUE;
}
-static gboolean
-handle_action (NMDBusDispatcher *dbus_dispatcher,
- GDBusMethodInvocation *context,
- const char *str_action,
- GVariant *connection_dict,
- GVariant *connection_props,
- GVariant *device_props,
- GVariant *device_proxy_props,
- GVariant *device_ip4_props,
- GVariant *device_ip6_props,
- GVariant *device_dhcp4_props,
- GVariant *device_dhcp6_props,
- const char *connectivity_state,
- const char *vpn_ip_iface,
- GVariant *vpn_proxy_props,
- GVariant *vpn_ip4_props,
- GVariant *vpn_ip6_props,
- gboolean request_debug,
- gpointer user_data)
+static void
+_method_call_action (GDBusMethodInvocation *invocation,
+ GVariant *parameters)
{
- Handler *h = user_data;
+ const char *action;
+ gs_unref_variant GVariant *connection = NULL;
+ gs_unref_variant GVariant *connection_properties = NULL;
+ gs_unref_variant GVariant *device_properties = NULL;
+ gs_unref_variant GVariant *device_proxy_properties = NULL;
+ gs_unref_variant GVariant *device_ip4_config = NULL;
+ gs_unref_variant GVariant *device_ip6_config = NULL;
+ gs_unref_variant GVariant *device_dhcp4_config = NULL;
+ gs_unref_variant GVariant *device_dhcp6_config = NULL;
+ const char *connectivity_state;
+ const char *vpn_ip_iface;
+ gs_unref_variant GVariant *vpn_proxy_properties = NULL;
+ gs_unref_variant GVariant *vpn_ip4_config = NULL;
+ gs_unref_variant GVariant *vpn_ip6_config = NULL;
+ gboolean debug;
GSList *sorted_scripts = NULL;
GSList *iter;
Request *request;
@@ -723,33 +703,65 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
guint i, num_nowait = 0;
const char *error_message = NULL;
- sorted_scripts = find_scripts (str_action);
+ g_variant_get (parameters, "("
+ "&s" /* action */
+ "@a{sa{sv}}" /* connection */
+ "@a{sv}" /* connection_properties */
+ "@a{sv}" /* device_properties */
+ "@a{sv}" /* device_proxy_properties */
+ "@a{sv}" /* device_ip4_config */
+ "@a{sv}" /* device_ip6_config */
+ "@a{sv}" /* device_dhcp4_config */
+ "@a{sv}" /* device_dhcp6_config */
+ "&s" /* connectivity_state */
+ "&s" /* vpn_ip_iface */
+ "@a{sv}" /* vpn_proxy_properties */
+ "@a{sv}" /* vpn_ip4_config */
+ "@a{sv}" /* vpn_ip6_config */
+ "b" /* debug */
+ ")",
+ &action,
+ &connection,
+ &connection_properties,
+ &device_properties,
+ &device_proxy_properties,
+ &device_ip4_config,
+ &device_ip6_config,
+ &device_dhcp4_config,
+ &device_dhcp6_config,
+ &connectivity_state,
+ &vpn_ip_iface,
+ &vpn_proxy_properties,
+ &vpn_ip4_config,
+ &vpn_ip6_config,
+ &debug);
request = g_slice_new0 (Request);
- request->request_id = ++request_id_counter;
- request->handler = h;
- request->debug = request_debug || debug;
- request->context = context;
- request->action = g_strdup (str_action);
-
- request->envp = nm_dispatcher_utils_construct_envp (str_action,
- connection_dict,
- connection_props,
- device_props,
- device_proxy_props,
- device_ip4_props,
- device_ip6_props,
- device_dhcp4_props,
- device_dhcp6_props,
+ request->request_id = ++gl.request_id_counter;
+ request->debug = debug || gl.debug;
+ request->context = invocation;
+ request->action = g_strdup (action);
+
+ request->envp = nm_dispatcher_utils_construct_envp (action,
+ connection,
+ connection_properties,
+ device_properties,
+ device_proxy_properties,
+ device_ip4_config,
+ device_ip6_config,
+ device_dhcp4_config,
+ device_dhcp6_config,
connectivity_state,
vpn_ip_iface,
- vpn_proxy_props,
- vpn_ip4_props,
- vpn_ip6_props,
+ vpn_proxy_properties,
+ vpn_ip4_config,
+ vpn_ip6_config,
&request->iface,
&error_message);
request->scripts = g_ptr_array_new_full (5, script_info_free);
+
+ sorted_scripts = find_scripts (request);
for (iter = sorted_scripts; iter; iter = g_slist_next (iter)) {
ScriptInfo *s;
@@ -761,11 +773,11 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
}
g_slist_free (sorted_scripts);
- _LOG_R_I (request, "new request (%u scripts)", request->scripts->len);
- if ( _LOG_R_D_enabled (request)
+ _LOG_R_D (request, "new request (%u scripts)", request->scripts->len);
+ if ( _LOG_R_T_enabled (request)
&& request->envp) {
for (p = request->envp; *p; p++)
- _LOG_R_D (request, "environment: %s", *p);
+ _LOG_R_T (request, "environment: %s", *p);
}
if (error_message || request->scripts->len == 0) {
@@ -774,18 +786,18 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
if (error_message)
_LOG_R_W (request, "completed: invalid request: %s", error_message);
else
- _LOG_R_I (request, "completed: no scripts");
+ _LOG_R_D (request, "completed: no scripts");
results = g_variant_new_array (G_VARIANT_TYPE ("(sus)"), NULL, 0);
- g_dbus_method_invocation_return_value (context, g_variant_new ("(@a(sus))", results));
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("(@a(sus))", results));
request->num_scripts_done = request->scripts->len;
request_free (request);
- return TRUE;
+ return;
}
- nm_clear_g_source (&quit_id);
+ nm_clear_g_source (&gl.quit_id);
- h->num_requests_pending++;
+ gl.num_requests_pending++;
for (i = 0; i < request->scripts->len; i++) {
ScriptInfo *s = g_ptr_array_index (request->scripts, i);
@@ -800,8 +812,8 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
/* The request has at least one wait script.
* Try next_request() to schedule the request for
* execution. This either enqueues the request or
- * sets it as h->current_request. */
- if (next_request (h, request)) {
+ * sets it as gl.current_request. */
+ if (next_request (request)) {
/* @request is now @current_request. Go ahead and
* schedule the first wait script. */
if (!dispatch_one_script (request)) {
@@ -809,7 +821,7 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
* request. Try complete_request(). */
complete_request (request);
- if (next_request (h, NULL)) {
+ if (next_request (NULL)) {
/* As @request was successfully scheduled as next_request(), there is no
* other request in queue that can be scheduled afterwards. Assert against
* that, but call next_request() to clear current_request. */
@@ -822,24 +834,20 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
* the request right away (we might have failed to schedule any
* of the scripts). It will be either completed now, or later
* when the pending scripts return.
- * We don't enqueue it to h->requests_waiting.
+ * We don't enqueue it to gl.requests_waiting.
* There is no need to handle next_request(), because @request is
* not the current request anyway and does not interfere with requests
* that have any "wait" scripts. */
complete_request (request);
}
-
- return TRUE;
}
-static gboolean ever_acquired_name = FALSE;
-
static void
on_name_acquired (GDBusConnection *connection,
const char *name,
gpointer user_data)
{
- ever_acquired_name = TRUE;
+ gl.ever_acquired_name = TRUE;
}
static void
@@ -848,22 +856,79 @@ on_name_lost (GDBusConnection *connection,
gpointer user_data)
{
if (!connection) {
- if (!ever_acquired_name) {
- g_warning ("Could not get the system bus. Make sure the message bus daemon is running!");
- exit (1);
+ if (!gl.ever_acquired_name) {
+ _LOG_X_W ("Could not get the system bus. Make sure the message bus daemon is running!");
+ gl.exit_with_failure = TRUE;
} else {
- g_message ("System bus stopped. Exiting");
- exit (0);
+ _LOG_X_I ("System bus stopped. Exiting");
+ }
+ } else if (!gl.ever_acquired_name) {
+ _LOG_X_W ("Could not acquire the " NM_DISPATCHER_DBUS_SERVICE " service.");
+ gl.exit_with_failure = TRUE;
+ } else
+ _LOG_X_I ("Lost the " NM_DISPATCHER_DBUS_SERVICE " name. Exiting");
+
+ g_main_loop_quit (gl.loop);
+}
+
+static void
+_method_call (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ if (nm_streq (interface_name, NM_DISPATCHER_DBUS_INTERFACE)) {
+ if (nm_streq (method_name, "Action")) {
+ _method_call_action (invocation, parameters);
+ return;
}
- } else if (!ever_acquired_name) {
- g_warning ("Could not acquire the " NM_DISPATCHER_DBUS_SERVICE " service.");
- exit (1);
- } else {
- g_message ("Lost the " NM_DISPATCHER_DBUS_SERVICE " name. Exiting");
- exit (0);
}
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_UNKNOWN_METHOD,
+ "Unknown method %s",
+ method_name);
}
+static GDBusInterfaceInfo *const interface_info = NM_DEFINE_GDBUS_INTERFACE_INFO (
+ NM_DISPATCHER_DBUS_INTERFACE,
+ .methods = NM_DEFINE_GDBUS_METHOD_INFOS (
+ NM_DEFINE_GDBUS_METHOD_INFO (
+ "Action",
+ .in_args = NM_DEFINE_GDBUS_ARG_INFOS (
+ NM_DEFINE_GDBUS_ARG_INFO ("action", "s"),
+ NM_DEFINE_GDBUS_ARG_INFO ("connection", "a{sa{sv}}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("connection_properties", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("device_properties", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("device_proxy_properties", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("device_ip4_config", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("device_ip6_config", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("device_dhcp4_config", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("device_dhcp6_config", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("connectivity_state", "s"),
+ NM_DEFINE_GDBUS_ARG_INFO ("vpn_ip_iface", "s"),
+ NM_DEFINE_GDBUS_ARG_INFO ("vpn_proxy_properties", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("vpn_ip4_config", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("vpn_ip6_config", "a{sv}"),
+ NM_DEFINE_GDBUS_ARG_INFO ("debug", "b"),
+ ),
+ .out_args = NM_DEFINE_GDBUS_ARG_INFOS (
+ NM_DEFINE_GDBUS_ARG_INFO ("results", "a(sus)"),
+ ),
+ ),
+ ),
+);
+
+static const GDBusInterfaceVTable interface_vtable = {
+ .method_call = _method_call,
+};
+
+/*****************************************************************************/
+
static void
log_handler (const char *log_domain,
GLogLevelFlags log_level,
@@ -918,42 +983,55 @@ signal_handler (gpointer user_data)
{
int signo = GPOINTER_TO_INT (user_data);
- g_message ("Caught signal %d, shutting down...", signo);
- g_main_loop_quit (loop);
+ _LOG_X_I ("Caught signal %d, shutting down...", signo);
+ g_main_loop_quit (gl.loop);
- return G_SOURCE_REMOVE;
+ return G_SOURCE_CONTINUE;
}
-int
-main (int argc, char **argv)
+static gboolean
+parse_command_line (int *p_argc,
+ char ***p_argv,
+ GError **error)
{
GOptionContext *opt_ctx;
- GError *error = NULL;
- GDBusConnection *bus;
- Handler *handler;
-
GOptionEntry entries[] = {
- { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL },
- { "persist", 0, 0, G_OPTION_ARG_NONE, &persist, "Don't quit after a short timeout", NULL },
+ { "debug", 0, 0, G_OPTION_ARG_NONE, &gl.debug, "Output to console rather than syslog", NULL },
+ { "persist", 0, 0, G_OPTION_ARG_NONE, &gl.persist, "Don't quit after a short timeout", NULL },
{ NULL }
};
+ gboolean success;
opt_ctx = g_option_context_new (NULL);
g_option_context_set_summary (opt_ctx, "Executes scripts upon actions by NetworkManager.");
g_option_context_add_main_entries (opt_ctx, entries, NULL);
- if (!g_option_context_parse (opt_ctx, &argc, &argv, &error)) {
- g_warning ("Error parsing command line arguments: %s", error->message);
- g_error_free (error);
- return 1;
- }
+ success = g_option_context_parse (opt_ctx, p_argc, p_argv, error);
g_option_context_free (opt_ctx);
- g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM));
- g_unix_signal_add (SIGINT, signal_handler, GINT_TO_POINTER (SIGINT));
+ return success;
+}
- if (debug) {
+int
+main (int argc, char **argv)
+{
+ gs_free_error GError *error = NULL;
+ guint signal_id_term = 0;
+ guint signal_id_int = 0;
+ guint dbus_regist_id = 0;
+ guint dbus_own_name_id = 0;
+
+ if (!parse_command_line (&argc, &argv, &error)) {
+ _LOG_X_W ("Error parsing command line arguments: %s", error->message);
+ gl.exit_with_failure = TRUE;
+ goto done;
+ }
+
+ signal_id_term = g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM));
+ signal_id_int = g_unix_signal_add (SIGINT, signal_handler, GINT_TO_POINTER (SIGINT));
+
+ if (gl.debug) {
if (!g_getenv ("G_MESSAGES_DEBUG")) {
/* we log our regular messages using g_debug() and g_info().
* When we redirect glib logging to syslog, there is no problem.
@@ -964,45 +1042,75 @@ main (int argc, char **argv)
} else
logging_setup ();
- loop = g_main_loop_new (NULL, FALSE);
+ gl.loop = g_main_loop_new (NULL, FALSE);
- bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
- if (!bus) {
- g_warning ("Could not get the system bus (%s). Make sure the message bus daemon is running!",
- error->message);
- g_error_free (error);
- return 1;
+ gl.dbus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (!gl.dbus_connection) {
+ _LOG_X_W ("Could not get the system bus (%s). Make sure the message bus daemon is running!",
+ error->message);
+ gl.exit_with_failure = TRUE;
+ goto done;
}
- handler = g_object_new (HANDLER_TYPE, NULL);
- g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (handler->dbus_dispatcher),
- bus,
- NM_DISPATCHER_DBUS_PATH,
- &error);
- if (error) {
- g_warning ("Could not export Dispatcher D-Bus interface: %s", error->message);
- g_error_free (error);
- return 1;
+ gl.requests_waiting = g_queue_new ();
+
+ dbus_regist_id = g_dbus_connection_register_object (gl.dbus_connection,
+ NM_DISPATCHER_DBUS_PATH,
+ interface_info,
+ NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable),
+ NULL,
+ NULL,
+ &error);
+ if (dbus_regist_id == 0) {
+ _LOG_X_W ("Could not export Dispatcher D-Bus interface: %s", error->message);
+ gl.exit_with_failure = 1;
+ goto done;
}
- g_bus_own_name_on_connection (bus,
- NM_DISPATCHER_DBUS_SERVICE,
- G_BUS_NAME_OWNER_FLAGS_NONE,
- on_name_acquired,
- on_name_lost,
- NULL, NULL);
- g_object_unref (bus);
+ dbus_own_name_id = g_bus_own_name_on_connection (gl.dbus_connection,
+ NM_DISPATCHER_DBUS_SERVICE,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_name_acquired,
+ on_name_lost,
+ NULL, NULL);
quit_timeout_reschedule ();
- g_main_loop_run (loop);
+ g_main_loop_run (gl.loop);
+
+done:
+
+ if (gl.num_requests_pending > 0) {
+ /* this only happens when we quit due to SIGTERM (not due to the idle timer).
+ *
+ * Log a warning about pending scripts.
+ *
+ * Maybe we should notify NetworkManager that these scripts are left in an unknown state.
+ * But this is either a bug of a dispatcher script (not terminating in time).
+ *
+ * FIXME(shutdown): Also, currently NetworkManager behaves wrongly on shutdown.
+ * Note that systemd would not terminate NetworkManager-dispatcher before NetworkManager.
+ * It's NetworkManager's responsibility to keep running long enough so that all requests
+ * can complete (with a watchdog timer, and a warning that user provided scripts hang). */
+ _LOG_X_W ("exiting but there are still %u requests pending", gl.num_requests_pending);
+ }
+
+ if (dbus_own_name_id != 0)
+ g_bus_unown_name (nm_steal_int (&dbus_own_name_id));
+
+ if (dbus_regist_id != 0)
+ g_dbus_connection_unregister_object (gl.dbus_connection, nm_steal_int (&dbus_regist_id));
- g_queue_free (handler->requests_waiting);
- g_object_unref (handler);
+ nm_clear_pointer (&gl.requests_waiting, g_queue_free);
- if (!debug)
+ nm_clear_g_source (&signal_id_term);
+ nm_clear_g_source (&signal_id_int);
+ nm_clear_g_source (&gl.quit_id);
+ g_clear_pointer (&gl.loop, g_main_loop_unref);
+ g_clear_object (&gl.dbus_connection);
+
+ if (!gl.debug)
logging_shutdown ();
- return 0;
+ return gl.exit_with_failure ? 1 : 0;
}
-
diff --git a/dispatcher/tests/meson.build b/dispatcher/tests/meson.build
index 3da3c3e912..10d1c6a93f 100644
--- a/dispatcher/tests/meson.build
+++ b/dispatcher/tests/meson.build
@@ -7,7 +7,7 @@ incs = [
exe = executable(
test_unit,
- test_unit + '.c',
+ [ test_unit + '.c' ] + [ nmdbus_dispatcher_sources ],
include_directories: incs,
dependencies: libnm_core_dep,
c_args: [
diff --git a/dispatcher/tests/test-dispatcher-envp.c b/dispatcher/tests/test-dispatcher-envp.c
index cdc3e6b25b..b1205c3235 100644
--- a/dispatcher/tests/test-dispatcher-envp.c
+++ b/dispatcher/tests/test-dispatcher-envp.c
@@ -28,6 +28,8 @@
#include "nm-utils/nm-test-utils.h"
+#include "nmdbus-dispatcher.h"
+
#define TEST_DIR NM_BUILD_SRCDIR"/dispatcher/tests"
/*****************************************************************************/
@@ -637,6 +639,17 @@ test_up_empty_vpn_iface (void)
/*****************************************************************************/
+static void
+test_gdbus_codegen (void)
+{
+ gs_unref_object NMDBusDispatcher *dbus_dispatcher = NULL;
+
+ dbus_dispatcher = nmdbus_dispatcher_skeleton_new ();
+ g_assert (NMDBUS_IS_DISPATCHER_SKELETON (dbus_dispatcher));
+}
+
+/*****************************************************************************/
+
NMTST_DEFINE ();
int
@@ -653,6 +666,8 @@ main (int argc, char **argv)
g_test_add_func ("/dispatcher/up_empty_vpn_iface", test_up_empty_vpn_iface);
+ g_test_add_func ("/dispatcher/gdbus-codegen", test_gdbus_codegen);
+
return g_test_run ();
}
diff --git a/shared/nm-glib-aux/nm-macros-internal.h b/shared/nm-glib-aux/nm-macros-internal.h
index 77288dde58..1ff90dc5d4 100644
--- a/shared/nm-glib-aux/nm-macros-internal.h
+++ b/shared/nm-glib-aux/nm-macros-internal.h
@@ -635,8 +635,10 @@ NM_G_ERROR_MSG (GError *error)
* It's useful to check the let the compiler ensure that @value is
* of a certain type. */
#define _NM_ENSURE_TYPE(type, value) (_Generic ((value), type: (value)))
+#define _NM_ENSURE_TYPE_CONST(type, value) (_Generic ((value), const type: ((const type) (value)), type: ((const type) (value))))
#else
#define _NM_ENSURE_TYPE(type, value) (value)
+#define _NM_ENSURE_TYPE_CONST(type, value) ((const type) (value))
#endif
#if _NM_CC_SUPPORT_GENERIC
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index d752f3b138..493288c197 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -328,16 +328,18 @@ typedef struct _NMDevicePrivate {
ActivationHandleData act_handle4; /* for layer2 and IPv4. */
ActivationHandleData act_handle6;
guint recheck_assume_id;
+
struct {
guint call_id;
NMDeviceStateReason available_reason;
NMDeviceStateReason unavailable_reason;
- } recheck_available;
+ } recheck_available;
+
struct {
- guint call_id;
+ NMDispatcherCallId *call_id;
NMDeviceState post_state;
NMDeviceStateReason post_state_reason;
- } dispatcher;
+ } dispatcher;
/* Link stuff */
guint link_connected_id;
@@ -12373,29 +12375,31 @@ nm_device_get_ip6_config (NMDevice *self)
/*****************************************************************************/
-static void
+static gboolean
dispatcher_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- if (priv->dispatcher.call_id) {
- nm_dispatcher_call_cancel (priv->dispatcher.call_id);
- priv->dispatcher.call_id = 0;
- priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
- priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
- }
+ if (!priv->dispatcher.call_id)
+ return FALSE;
+
+ nm_dispatcher_call_cancel (g_steal_pointer (&priv->dispatcher.call_id));
+ priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
+ priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
+ return TRUE;
}
static void
-dispatcher_complete_proceed_state (guint call_id, gpointer user_data)
+dispatcher_complete_proceed_state (NMDispatcherCallId *call_id, gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
g_return_if_fail (call_id == priv->dispatcher.call_id);
- priv->dispatcher.call_id = 0;
- nm_device_queue_state (self, priv->dispatcher.post_state,
+ priv->dispatcher.call_id = NULL;
+ nm_device_queue_state (self,
+ priv->dispatcher.post_state,
priv->dispatcher.post_state_reason);
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
@@ -12408,10 +12412,8 @@ ip_check_pre_up (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- if (priv->dispatcher.call_id != 0) {
- g_warn_if_reached ();
- dispatcher_cleanup (self);
- }
+ if (dispatcher_cleanup (self))
+ nm_assert_not_reached ();
priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
@@ -14822,7 +14824,7 @@ deactivate_async_ready (NMDevice *self,
}
static void
-deactivate_dispatcher_complete (guint call_id, gpointer user_data)
+deactivate_dispatcher_complete (NMDispatcherCallId *call_id, gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
@@ -14833,7 +14835,7 @@ deactivate_dispatcher_complete (guint call_id, gpointer user_data)
reason = priv->dispatcher.post_state_reason;
- priv->dispatcher.call_id = 0;
+ priv->dispatcher.call_id = NULL;
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
diff --git a/src/main.c b/src/main.c
index 4737d2a164..e9e2c4306c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -436,8 +436,6 @@ main (int argc, char *argv[])
nm_manager_dbus_set_property_handle,
manager);
- nm_dispatcher_init ();
-
g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);
if (!nm_manager_start (manager, &error)) {
diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c
index 8ac18ed44a..d65f344949 100644
--- a/src/nm-dispatcher.c
+++ b/src/nm-dispatcher.c
@@ -44,8 +44,121 @@
#define _NMLOG_DOMAIN LOGD_DISPATCH
#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "dispatcher", __VA_ARGS__)
-static GDBusProxy *dispatcher_proxy;
-static GHashTable *requests = NULL;
+#define _NMLOG2_DOMAIN LOGD_DISPATCH
+#define _NMLOG2(level, request_id, log_ifname, log_con_uuid, ...) \
+ nm_log ((level), \
+ _NMLOG2_DOMAIN, \
+ (log_ifname), \
+ (log_con_uuid), \
+ "dispatcher: (%u) " \
+ _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
+ (request_id) \
+ _NM_UTILS_MACRO_REST (__VA_ARGS__))
+
+#define _NMLOG3_DOMAIN LOGD_DISPATCH
+#define _NMLOG3(level, call_id, ...) \
+ G_STMT_START { \
+ const NMDispatcherCallId *const _call_id = (call_id); \
+ \
+ _NMLOG2 (level, _call_id->request_id, _call_id->log_ifname, _call_id->log_con_uuid, __VA_ARGS__); \
+ } G_STMT_END
+
+/*****************************************************************************/
+
+struct NMDispatcherCallId {
+ NMDispatcherFunc callback;
+ gpointer user_data;
+ const char *log_ifname;
+ const char *log_con_uuid;
+ NMDispatcherAction action;
+ guint idle_id;
+ guint32 request_id;
+ char extra_strings[];
+};
+
+/*****************************************************************************/
+
+/* FIXME(shutdown): on shutdown, we should not run dispatcher scripts synchronously.
+ * Instead, we should of course still run them asynchronously.
+ *
+ * Also, we should wait for all pending requests to complete before exiting the main-loop
+ * (with a watchdog). If we hit a timeout, we log a warning and quit (but leave the scripts
+ * running).
+ *
+ * Finally, cleanup the global structures. */
+static struct {
+ GDBusConnection *dbus_connection;
+ GHashTable *requests;
+ guint request_id_counter;
+} gl;
+
+/*****************************************************************************/
+
+static NMDispatcherCallId *
+dispatcher_call_id_new (guint32 request_id,
+ NMDispatcherAction action,
+ NMDispatcherFunc callback,
+ gpointer user_data,
+ const char *log_ifname,
+ const char *log_con_uuid)
+{
+ NMDispatcherCallId *call_id;
+ gsize l_log_ifname;
+ gsize l_log_con_uuid;
+ char *extra_strings;
+
+ l_log_ifname = log_ifname ? (strlen (log_ifname) + 1) : 0u;
+ l_log_con_uuid = log_con_uuid ? (strlen (log_con_uuid) + 1) : 0u;
+
+ call_id = g_malloc (sizeof (NMDispatcherCallId) + l_log_ifname + l_log_con_uuid);
+
+ call_id->action = action;
+ call_id->request_id = request_id;
+ call_id->callback = callback;
+ call_id->user_data = user_data;
+ call_id->idle_id = 0;
+
+ extra_strings = &call_id->extra_strings[0];
+
+ if (log_ifname) {
+ call_id->log_ifname = extra_strings;
+ memcpy (extra_strings, log_ifname, l_log_ifname);
+ extra_strings += l_log_ifname;
+ } else
+ call_id->log_ifname = NULL;
+
+ if (log_con_uuid) {
+ call_id->log_con_uuid = extra_strings;
+ memcpy (extra_strings, log_con_uuid, l_log_con_uuid);
+ } else
+ call_id->log_con_uuid = NULL;
+
+ return call_id;
+}
+
+static void
+dispatcher_call_id_free (NMDispatcherCallId *call_id)
+{
+ nm_clear_g_source (&call_id->idle_id);
+ g_free (call_id);
+}
+
+/*****************************************************************************/
+
+
+static void
+_init_dispatcher (void)
+{
+ if (G_UNLIKELY (gl.requests == NULL)) {
+ gl.requests = g_hash_table_new (nm_direct_hash, NULL);
+ gl.dbus_connection = nm_g_object_ref (NM_MAIN_DBUS_CONNECTION_GET);
+
+ if (!gl.dbus_connection)
+ _LOGD ("No D-Bus connection to talk with NetworkManager-dispatcher service");
+ }
+}
+
+/*****************************************************************************/
static void
dump_proxy_to_props (NMProxyConfig *proxy, GVariantBuilder *builder)
@@ -287,39 +400,6 @@ fill_vpn_props (NMProxyConfig *proxy_config,
dump_ip6_to_props (ip6_config, ip6_builder);
}
-typedef struct {
- NMDispatcherAction action;
- guint request_id;
- NMDispatcherFunc callback;
- gpointer user_data;
- guint idle_id;
-} DispatchInfo;
-
-static void
-dispatcher_info_free (DispatchInfo *info)
-{
- if (info->idle_id)
- g_source_remove (info->idle_id);
- g_free (info);
-}
-
-static void
-_ensure_requests (void)
-{
- if (G_UNLIKELY (requests == NULL)) {
- requests = g_hash_table_new_full (nm_direct_hash,
- NULL,
- NULL,
- (GDestroyNotify) dispatcher_info_free);
- }
-}
-
-static void
-dispatcher_info_cleanup (DispatchInfo *info)
-{
- g_hash_table_remove (requests, GUINT_TO_POINTER (info->request_id));
-}
-
static const char *
dispatch_result_to_string (DispatchResult result)
{
@@ -339,63 +419,71 @@ dispatch_result_to_string (DispatchResult result)
}
static void
-dispatcher_results_process (guint request_id, NMDispatcherAction action, GVariantIter *results)
+dispatcher_results_process (guint32 request_id,
+ const char *log_ifname,
+ const char *log_con_uuid,
+ GVariant *v_results)
{
+ nm_auto_free_variant_iter GVariantIter *results = NULL;
const char *script, *err;
guint32 result;
- g_return_if_fail (results != NULL);
+ g_variant_get (v_results, "(a(sus))", &results);
if (g_variant_iter_n_children (results) == 0) {
- _LOGD ("(%u) succeeded but no scripts invoked", request_id);
+ _LOG2D (request_id, log_ifname, log_con_uuid, "succeeded but no scripts invoked");
return;
}
while (g_variant_iter_next (results, "(&su&s)", &script, &result, &err)) {
if (result == DISPATCH_RESULT_SUCCESS) {
- _LOGD ("(%u) %s succeeded", request_id, script);
+ _LOG2D (request_id, log_ifname, log_con_uuid, "%s succeeded", script);
} else {
- _LOGW ("(%u) %s failed (%s): %s",
- request_id,
- script,
- dispatch_result_to_string (result),
- err);
+ _LOG2W (request_id,
+ log_ifname,
+ log_con_uuid,
+ "%s failed (%s): %s",
+ script,
+ dispatch_result_to_string (result),
+ err);
}
}
}
static void
-dispatcher_done_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
+dispatcher_done_cb (GObject *source, GAsyncResult *result, gpointer user_data)
{
- DispatchInfo *info = user_data;
- GVariant *ret;
- GVariantIter *results;
- GError *error = NULL;
-
- ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result,
- G_VARIANT_TYPE ("(a(sus))"),
- &error);
- if (ret) {
- g_variant_get (ret, "(a(sus))", &results);
- dispatcher_results_process (info->request_id, info->action, results);
- g_variant_iter_free (results);
- g_variant_unref (ret);
- } else {
+ gs_unref_variant GVariant *ret = NULL;
+ gs_free_error GError *error = NULL;
+ NMDispatcherCallId *call_id = user_data;
+
+ nm_assert ((gpointer) source == gl.dbus_connection);
+
+ ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
+ result,
+ &error);
+ if (!ret) {
if (_nm_dbus_error_has_name (error, "org.freedesktop.systemd1.LoadFailed")) {
g_dbus_error_strip_remote_error (error);
- _LOGW ("(%u) failed to call dispatcher scripts: %s",
- info->request_id, error->message);
+ _LOG3W (call_id, "failed to call dispatcher scripts: %s",
+ error->message);
} else {
- _LOGD ("(%u) failed to call dispatcher scripts: %s",
- info->request_id, error->message);
+ _LOG3D (call_id, "failed to call dispatcher scripts: %s",
+ error->message);
}
- g_clear_error (&error);
+ } else {
+ dispatcher_results_process (call_id->request_id,
+ call_id->log_ifname,
+ call_id->log_con_uuid,
+ ret);
}
- if (info->callback)
- info->callback (info->request_id, info->user_data);
+ g_hash_table_remove (gl.requests, call_id);
- dispatcher_info_cleanup (info);
+ if (call_id->callback)
+ call_id->callback (call_id, call_id->user_data);
+
+ dispatcher_call_id_free (call_id);
}
static const char *action_table[] = {
@@ -416,8 +504,9 @@ static const char *action_table[] = {
static const char *
action_to_string (NMDispatcherAction action)
{
- g_assert ((gsize) action < G_N_ELEMENTS (action_table));
- return action_table[action];
+ if (G_UNLIKELY ((gsize) action >= G_N_ELEMENTS (action_table)))
+ g_return_val_if_reached (NULL);
+ return action_table[(gsize) action];
}
static gboolean
@@ -434,7 +523,7 @@ _dispatcher_call (NMDispatcherAction action,
NMIP6Config *vpn_ip6_config,
NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id)
+ NMDispatcherCallId **out_call_id)
{
GVariant *connection_dict;
GVariantBuilder connection_props;
@@ -442,47 +531,57 @@ _dispatcher_call (NMDispatcherAction action,
GVariantBuilder device_proxy_props;
GVariantBuilder device_ip4_props;
GVariantBuilder device_ip6_props;
- GVariant *device_dhcp4_props = NULL;
- GVariant *device_dhcp6_props = NULL;
+ gs_unref_variant GVariant *parameters_floating = NULL;
+ gs_unref_variant GVariant *device_dhcp4_props = NULL;
+ gs_unref_variant GVariant *device_dhcp6_props = NULL;
GVariantBuilder vpn_proxy_props;
GVariantBuilder vpn_ip4_props;
GVariantBuilder vpn_ip6_props;
- DispatchInfo *info = NULL;
- gboolean success = FALSE;
- GError *error = NULL;
- static guint request_counter = 0;
- guint reqid = ++request_counter;
+ NMDispatcherCallId *call_id;
+ guint request_id;
const char *connectivity_state_string = "UNKNOWN";
+ const char *log_ifname;
+ const char *log_con_uuid;
- if (!dispatcher_proxy)
- return FALSE;
+ g_return_val_if_fail (!blocking || (!callback && !user_data), FALSE);
+
+ NM_SET_OUT (out_call_id, NULL);
- /* Wrapping protection */
- if (G_UNLIKELY (!reqid))
- reqid = ++request_counter;
+ _init_dispatcher ();
+
+ if (!gl.dbus_connection)
+ return FALSE;
- g_assert (!blocking || (!callback && !user_data));
+ log_ifname = device ? nm_device_get_iface (device) : NULL;
+ log_con_uuid = settings_connection ? nm_settings_connection_get_uuid (settings_connection) : NULL;
- _ensure_requests ();
+ request_id = ++gl.request_id_counter;
+ if (G_UNLIKELY (!request_id))
+ request_id = ++gl.request_id_counter;
/* All actions except 'hostname' and 'connectivity-change' require a device */
if ( action == NM_DISPATCHER_ACTION_HOSTNAME
|| action == NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE) {
- _LOGD ("(%u) dispatching action '%s'%s",
- reqid, action_to_string (action),
- blocking
+ _LOG2D (request_id,
+ log_ifname,
+ log_con_uuid,
+ "dispatching action '%s'%s",
+ action_to_string (action),
+ blocking
? " (blocking)"
: (callback ? " (with callback)" : ""));
} else {
g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
- _LOGD ("(%u) (%s) dispatching action '%s'%s",
- reqid,
- vpn_iface ?: nm_device_get_iface(device),
- action_to_string (action),
- blocking
- ? " (blocking)"
- : (callback ? " (with callback)" : ""));
+ _LOG2D (request_id,
+ log_ifname,
+ log_con_uuid,
+ "(%s) dispatching action '%s'%s",
+ vpn_iface ?: nm_device_get_iface (device),
+ action_to_string (action),
+ blocking
+ ? " (blocking)"
+ : (callback ? " (with callback)" : ""));
}
if (applied_connection)
@@ -542,90 +641,72 @@ _dispatcher_call (NMDispatcherAction action,
}
}
- if (!device_dhcp4_props)
- device_dhcp4_props = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0));
- if (!device_dhcp6_props)
- device_dhcp6_props = g_variant_ref_sink (g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0));
-
connectivity_state_string = nm_connectivity_state_to_string (connectivity_state);
+ parameters_floating = g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}a{sv}b)",
+ action_to_string (action),
+ connection_dict,
+ &connection_props,
+ &device_props,
+ &device_proxy_props,
+ &device_ip4_props,
+ &device_ip6_props,
+ device_dhcp4_props ?: g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0),
+ device_dhcp6_props ?: g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0),
+ connectivity_state_string,
+ vpn_iface ?: "",
+ &vpn_proxy_props,
+ &vpn_ip4_props,
+ &vpn_ip6_props,
+ nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH));
+
/* Send the action to the dispatcher */
if (blocking) {
- GVariant *ret;
- GVariantIter *results;
-
- ret = _nm_dbus_proxy_call_sync (dispatcher_proxy, "Action",
- g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}a{sv}b)",
- action_to_string (action),
- connection_dict,
- &connection_props,
- &device_props,
- &device_proxy_props,
- &device_ip4_props,
- &device_ip6_props,
- device_dhcp4_props,
- device_dhcp6_props,
- connectivity_state_string,
- vpn_iface ?: "",
- &vpn_proxy_props,
- &vpn_ip4_props,
- &vpn_ip6_props,
- nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH)),
- G_VARIANT_TYPE ("(a(sus))"),
- G_DBUS_CALL_FLAGS_NONE, CALL_TIMEOUT,
- NULL, &error);
- if (ret) {
- g_variant_get (ret, "(a(sus))", &results);
- dispatcher_results_process (reqid, action, results);
- g_variant_iter_free (results);
- g_variant_unref (ret);
- success = TRUE;
- } else {
+ gs_unref_variant GVariant *ret = NULL;
+ gs_free_error GError *error = NULL;
+
+ ret = g_dbus_connection_call_sync (gl.dbus_connection,
+ NM_DISPATCHER_DBUS_SERVICE,
+ NM_DISPATCHER_DBUS_PATH,
+ NM_DISPATCHER_DBUS_INTERFACE,
+ "Action",
+ g_steal_pointer (&parameters_floating),
+ G_VARIANT_TYPE ("(a(sus))"),
+ G_DBUS_CALL_FLAGS_NONE,
+ CALL_TIMEOUT,
+ NULL,
+ &error);
+ if (!ret) {
g_dbus_error_strip_remote_error (error);
- _LOGW ("(%u) failed: %s", reqid, error->message);
- g_clear_error (&error);
- success = FALSE;
+ _LOG2W (request_id, log_ifname, log_con_uuid, "failed: %s", error->message);
+ return FALSE;
}
- } else {
- info = g_malloc0 (sizeof (*info));
- info->action = action;
- info->request_id = reqid;
- info->callback = callback;
- info->user_data = user_data;
- g_dbus_proxy_call (dispatcher_proxy, "Action",
- g_variant_new ("(s@a{sa{sv}}a{sv}a{sv}a{sv}a{sv}a{sv}@a{sv}@a{sv}ssa{sv}a{sv}a{sv}b)",
- action_to_string (action),
- connection_dict,
- &connection_props,
- &device_props,
- &device_proxy_props,
- &device_ip4_props,
- &device_ip6_props,
- device_dhcp4_props,
- device_dhcp6_props,
- connectivity_state_string,
- vpn_iface ?: "",
- &vpn_proxy_props,
- &vpn_ip4_props,
- &vpn_ip6_props,
- nm_logging_enabled (LOGL_DEBUG, LOGD_DISPATCH)),
- G_DBUS_CALL_FLAGS_NONE, CALL_TIMEOUT,
- NULL, dispatcher_done_cb, info);
- success = TRUE;
+ dispatcher_results_process (request_id, log_ifname, log_con_uuid, ret);
+ return TRUE;
}
- g_variant_unref (device_dhcp4_props);
- g_variant_unref (device_dhcp6_props);
-
- if (success && info) {
- /* Track the request in case of cancelation */
- g_hash_table_insert (requests, GUINT_TO_POINTER (info->request_id), info);
- if (out_call_id)
- *out_call_id = info->request_id;
- } else if (out_call_id)
- *out_call_id = 0;
-
- return success;
+ call_id = dispatcher_call_id_new (request_id,
+ action,
+ callback,
+ user_data,
+ log_ifname,
+ log_con_uuid);
+
+ g_dbus_connection_call (gl.dbus_connection,
+ NM_DISPATCHER_DBUS_SERVICE,
+ NM_DISPATCHER_DBUS_PATH,
+ NM_DISPATCHER_DBUS_INTERFACE,
+ "Action",
+ g_steal_pointer (&parameters_floating),
+ G_VARIANT_TYPE ("(a(sus))"),
+ G_DBUS_CALL_FLAGS_NONE,
+ CALL_TIMEOUT,
+ NULL,
+ dispatcher_done_cb,
+ call_id);
+ g_hash_table_add (gl.requests, call_id);
+ NM_SET_OUT (out_call_id, call_id);
+ return TRUE;
}
/**
@@ -642,7 +723,7 @@ _dispatcher_call (NMDispatcherAction action,
gboolean
nm_dispatcher_call_hostname (NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id)
+ NMDispatcherCallId **out_call_id)
{
return _dispatcher_call (NM_DISPATCHER_ACTION_HOSTNAME, FALSE,
NULL, NULL, NULL, FALSE,
@@ -673,7 +754,7 @@ nm_dispatcher_call_device (NMDispatcherAction action,
NMActRequest *act_request,
NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id)
+ NMDispatcherCallId **out_call_id)
{
nm_assert (NM_IS_DEVICE (device));
if (!act_request) {
@@ -757,7 +838,7 @@ nm_dispatcher_call_vpn (NMDispatcherAction action,
NMIP6Config *vpn_ip6_config,
NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id)
+ NMDispatcherCallId **out_call_id)
{
return _dispatcher_call (action, FALSE,
parent_device,
@@ -821,7 +902,7 @@ gboolean
nm_dispatcher_call_connectivity (NMConnectivityState connectivity_state,
NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id)
+ NMDispatcherCallId **out_call_id)
{
return _dispatcher_call (NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE, FALSE,
NULL, NULL, NULL, FALSE,
@@ -831,40 +912,16 @@ nm_dispatcher_call_connectivity (NMConnectivityState connectivity_state,
}
void
-nm_dispatcher_call_cancel (guint call_id)
+nm_dispatcher_call_cancel (NMDispatcherCallId *call_id)
{
- DispatchInfo *info;
-
- _ensure_requests ();
+ if ( !call_id
+ || g_hash_table_lookup (gl.requests, call_id) != call_id
+ || !call_id->callback)
+ g_return_if_reached ();
/* Canceling just means the callback doesn't get called, so set the
* DispatcherInfo's callback to NULL.
*/
- info = g_hash_table_lookup (requests, GUINT_TO_POINTER (call_id));
- g_return_if_fail (info);
-
- if (info && info->callback) {
- _LOGD ("(%u) cancelling dispatcher callback action", call_id);
- info->callback = NULL;
- }
+ _LOG3D (call_id, "cancelling dispatcher callback action");
+ call_id->callback = NULL;
}
-
-void
-nm_dispatcher_init (void)
-{
- GError *error = NULL;
-
- dispatcher_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
- G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
- NULL,
- NM_DISPATCHER_DBUS_SERVICE,
- NM_DISPATCHER_DBUS_PATH,
- NM_DISPATCHER_DBUS_INTERFACE,
- NULL, &error);
- if (!dispatcher_proxy) {
- _LOGE ("could not get dispatcher proxy! %s", error->message);
- g_clear_error (&error);
- }
-}
-
diff --git a/src/nm-dispatcher.h b/src/nm-dispatcher.h
index 1cdeeb882a..3c79f3bbfb 100644
--- a/src/nm-dispatcher.h
+++ b/src/nm-dispatcher.h
@@ -39,18 +39,20 @@ typedef enum {
NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE
} NMDispatcherAction;
-typedef void (*NMDispatcherFunc) (guint call_id, gpointer user_data);
+typedef struct NMDispatcherCallId NMDispatcherCallId;
+
+typedef void (*NMDispatcherFunc) (NMDispatcherCallId *call_id, gpointer user_data);
gboolean nm_dispatcher_call_hostname (NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id);
+ NMDispatcherCallId **out_call_id);
gboolean nm_dispatcher_call_device (NMDispatcherAction action,
NMDevice *device,
NMActRequest *act_request,
NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id);
+ NMDispatcherCallId **out_call_id);
gboolean nm_dispatcher_call_device_sync (NMDispatcherAction action,
NMDevice *device,
@@ -66,7 +68,7 @@ gboolean nm_dispatcher_call_vpn (NMDispatcherAction action,
NMIP6Config *vpn_ip6_config,
NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id);
+ NMDispatcherCallId **out_call_id);
gboolean nm_dispatcher_call_vpn_sync (NMDispatcherAction action,
NMSettingsConnection *settings_connection,
@@ -80,10 +82,8 @@ gboolean nm_dispatcher_call_vpn_sync (NMDispatcherAction action,
gboolean nm_dispatcher_call_connectivity (NMConnectivityState state,
NMDispatcherFunc callback,
gpointer user_data,
- guint *out_call_id);
-
-void nm_dispatcher_call_cancel (guint call_id);
+ NMDispatcherCallId **out_call_id);
-void nm_dispatcher_init (void);
+void nm_dispatcher_call_cancel (NMDispatcherCallId *call_id);
#endif /* __NM_DISPATCHER_H__ */
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index 2c4f33359f..99bcd02712 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -103,7 +103,7 @@ typedef struct {
char *username;
VpnState vpn_state;
- guint dispatcher_id;
+ NMDispatcherCallId *dispatcher_id;
NMActiveConnectionStateReason failure_reason;
NMVpnServiceState service_state;
@@ -418,22 +418,28 @@ vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev)
}
static void
-dispatcher_pre_down_done (guint call_id, gpointer user_data)
+dispatcher_pre_down_done (NMDispatcherCallId *call_id, gpointer user_data)
{
NMVpnConnection *self = NM_VPN_CONNECTION (user_data);
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
- priv->dispatcher_id = 0;
+ nm_assert (call_id);
+ nm_assert (priv->dispatcher_id == call_id);
+
+ priv->dispatcher_id = NULL;
_set_vpn_state (self, STATE_DISCONNECTED, NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED, FALSE);
}
static void
-dispatcher_pre_up_done (guint call_id, gpointer user_data)
+dispatcher_pre_up_done (NMDispatcherCallId *call_id, gpointer user_data)
{
NMVpnConnection *self = NM_VPN_CONNECTION (user_data);
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
- priv->dispatcher_id = 0;
+ nm_assert (call_id);
+ nm_assert (priv->dispatcher_id == call_id);
+
+ priv->dispatcher_id = NULL;
_set_vpn_state (self, STATE_ACTIVATED, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE);
}
@@ -442,10 +448,8 @@ dispatcher_cleanup (NMVpnConnection *self)
{
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
- if (priv->dispatcher_id) {
- nm_dispatcher_call_cancel (priv->dispatcher_id);
- priv->dispatcher_id = 0;
- }
+ if (priv->dispatcher_id)
+ nm_dispatcher_call_cancel (g_steal_pointer (&priv->dispatcher_id));
}
static void