dispatcher: merge branch 'th/dispatcher-cleanup'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/162
This commit is contained in:
49
Makefile.am
49
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)
|
||||
|
@@ -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
|
||||
|
@@ -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',
|
||||
|
@@ -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__)); \
|
||||
} G_STMT_END
|
||||
|
||||
#define _LOG(_request, _script, log_always, print_cmd, ...) \
|
||||
G_STMT_START { \
|
||||
const Request *__request = (_request); \
|
||||
const ScriptInfo *__script = (_script); \
|
||||
\
|
||||
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__); \
|
||||
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
|
||||
|
||||
static gboolean
|
||||
_LOG_R_D_enabled (const Request *request)
|
||||
{
|
||||
return request->debug;
|
||||
}
|
||||
#define __LOG_print_R(print_cmd, _request, ...) \
|
||||
G_STMT_START { \
|
||||
__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_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_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_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__)
|
||||
#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); \
|
||||
\
|
||||
nm_assert (_request); \
|
||||
if (enabled_cmd) \
|
||||
__LOG_print_R (print_cmd, _request, ": "__VA_ARGS__); \
|
||||
} G_STMT_END
|
||||
|
||||
#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__)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
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->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 (str_action,
|
||||
connection_dict,
|
||||
connection_props,
|
||||
device_props,
|
||||
device_proxy_props,
|
||||
device_ip4_props,
|
||||
device_ip6_props,
|
||||
device_dhcp4_props,
|
||||
device_dhcp6_props,
|
||||
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 (!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);
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
g_queue_free (handler->requests_waiting);
|
||||
g_object_unref (handler);
|
||||
done:
|
||||
|
||||
if (!debug)
|
||||
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));
|
||||
|
||||
nm_clear_pointer (&gl.requests_waiting, g_queue_free);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@@ -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: [
|
||||
|
@@ -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 ();
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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)) {
|
||||
|
@@ -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;
|
||||
gs_unref_variant GVariant *ret = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
NMDispatcherCallId *call_id = user_data;
|
||||
|
||||
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 {
|
||||
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)
|
||||
g_return_val_if_fail (!blocking || (!callback && !user_data), FALSE);
|
||||
|
||||
NM_SET_OUT (out_call_id, NULL);
|
||||
|
||||
_init_dispatcher ();
|
||||
|
||||
if (!gl.dbus_connection)
|
||||
return FALSE;
|
||||
|
||||
/* Wrapping protection */
|
||||
if (G_UNLIKELY (!reqid))
|
||||
reqid = ++request_counter;
|
||||
log_ifname = device ? nm_device_get_iface (device) : NULL;
|
||||
log_con_uuid = settings_connection ? nm_settings_connection_get_uuid (settings_connection) : NULL;
|
||||
|
||||
g_assert (!blocking || (!callback && !user_data));
|
||||
|
||||
_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;
|
||||
gs_unref_variant GVariant *ret = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
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 {
|
||||
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 (¶meters_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);
|
||||
call_id = dispatcher_call_id_new (request_id,
|
||||
action,
|
||||
callback,
|
||||
user_data,
|
||||
log_ifname,
|
||||
log_con_uuid);
|
||||
|
||||
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;
|
||||
g_dbus_connection_call (gl.dbus_connection,
|
||||
NM_DISPATCHER_DBUS_SERVICE,
|
||||
NM_DISPATCHER_DBUS_PATH,
|
||||
NM_DISPATCHER_DBUS_INTERFACE,
|
||||
"Action",
|
||||
g_steal_pointer (¶meters_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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);
|
||||
NMDispatcherCallId **out_call_id);
|
||||
|
||||
void nm_dispatcher_call_cancel (guint call_id);
|
||||
|
||||
void nm_dispatcher_init (void);
|
||||
void nm_dispatcher_call_cancel (NMDispatcherCallId *call_id);
|
||||
|
||||
#endif /* __NM_DISPATCHER_H__ */
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user