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
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
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
|
libexec_PROGRAMS += dispatcher/nm-dispatcher
|
||||||
|
|
||||||
noinst_LTLIBRARIES += \
|
noinst_LTLIBRARIES += \
|
||||||
@@ -3905,25 +3924,6 @@ dispatcher_cppflags = \
|
|||||||
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT \
|
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT \
|
||||||
$(NULL)
|
$(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_libnm_dispatcher_core_la_SOURCES = \
|
||||||
dispatcher/nm-dispatcher-utils.c \
|
dispatcher/nm-dispatcher-utils.c \
|
||||||
dispatcher/nm-dispatcher-utils.h \
|
dispatcher/nm-dispatcher-utils.h \
|
||||||
@@ -3939,8 +3939,6 @@ dispatcher_nm_dispatcher_SOURCES = \
|
|||||||
dispatcher/nm-dispatcher.c \
|
dispatcher/nm-dispatcher.c \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
nodist_dispatcher_nm_dispatcher_SOURCES = $(dispatcher_nmdbus_dispatcher_sources)
|
|
||||||
|
|
||||||
dispatcher_nm_dispatcher_CPPFLAGS = $(dispatcher_cppflags)
|
dispatcher_nm_dispatcher_CPPFLAGS = $(dispatcher_cppflags)
|
||||||
|
|
||||||
dispatcher_nm_dispatcher_LDFLAGS = \
|
dispatcher_nm_dispatcher_LDFLAGS = \
|
||||||
@@ -3998,12 +3996,21 @@ dispatcher_tests_test_dispatcher_envp_CPPFLAGS = \
|
|||||||
-I$(srcdir)/libnm \
|
-I$(srcdir)/libnm \
|
||||||
-I$(builddir)/libnm \
|
-I$(builddir)/libnm \
|
||||||
-I$(srcdir)/dispatcher \
|
-I$(srcdir)/dispatcher \
|
||||||
|
-I$(builddir)/dispatcher \
|
||||||
-DNETWORKMANAGER_COMPILATION_TEST \
|
-DNETWORKMANAGER_COMPILATION_TEST \
|
||||||
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT \
|
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_CLIENT \
|
||||||
$(GLIB_CFLAGS) \
|
$(GLIB_CFLAGS) \
|
||||||
$(SANITIZER_EXEC_CFLAGS) \
|
$(SANITIZER_EXEC_CFLAGS) \
|
||||||
$(NULL)
|
$(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 = \
|
dispatcher_tests_test_dispatcher_envp_LDFLAGS = \
|
||||||
$(SANITIZER_EXEC_LDFLAGS) \
|
$(SANITIZER_EXEC_LDFLAGS) \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@@ -1,6 +1,12 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Network Manager Script Dispatcher Service
|
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]
|
[Service]
|
||||||
Type=dbus
|
Type=dbus
|
||||||
BusName=org.freedesktop.nm_dispatcher
|
BusName=org.freedesktop.nm_dispatcher
|
||||||
|
@@ -44,7 +44,7 @@ libnm_dispatcher_core = static_library(
|
|||||||
|
|
||||||
sources = files('nm-dispatcher.c')
|
sources = files('nm-dispatcher.c')
|
||||||
|
|
||||||
sources += gnome.gdbus_codegen(
|
nmdbus_dispatcher_sources = gnome.gdbus_codegen(
|
||||||
'nmdbus-dispatcher',
|
'nmdbus-dispatcher',
|
||||||
name + '.xml',
|
name + '.xml',
|
||||||
interface_prefix: 'org.freedesktop',
|
interface_prefix: 'org.freedesktop',
|
||||||
|
@@ -34,74 +34,24 @@
|
|||||||
#include "nm-libnm-core-aux/nm-dispatcher-api.h"
|
#include "nm-libnm-core-aux/nm-dispatcher-api.h"
|
||||||
#include "nm-dispatcher-utils.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 Request Request;
|
||||||
|
|
||||||
typedef struct {
|
static struct {
|
||||||
GObject parent;
|
GDBusConnection *dbus_connection;
|
||||||
|
GMainLoop *loop;
|
||||||
/* Private data */
|
gboolean debug;
|
||||||
NMDBusDispatcher *dbus_dispatcher;
|
gboolean persist;
|
||||||
|
guint quit_id;
|
||||||
|
guint request_id_counter;
|
||||||
|
gboolean ever_acquired_name;
|
||||||
|
bool exit_with_failure;
|
||||||
|
|
||||||
Request *current_request;
|
Request *current_request;
|
||||||
GQueue *requests_waiting;
|
GQueue *requests_waiting;
|
||||||
int num_requests_pending;
|
int num_requests_pending;
|
||||||
} Handler;
|
} gl;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Request *request;
|
Request *request;
|
||||||
@@ -117,8 +67,6 @@ typedef struct {
|
|||||||
} ScriptInfo;
|
} ScriptInfo;
|
||||||
|
|
||||||
struct Request {
|
struct Request {
|
||||||
Handler *handler;
|
|
||||||
|
|
||||||
guint request_id;
|
guint request_id;
|
||||||
|
|
||||||
GDBusMethodInvocation *context;
|
GDBusMethodInvocation *context;
|
||||||
@@ -135,52 +83,86 @@ struct Request {
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#define __LOG_print(print_cmd, _request, _script, ...) \
|
#define __LOG_print(print_cmd, ...) \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
nm_assert ((_request) && (!(_script) || (_script)->request == (_request))); \
|
if (FALSE) { \
|
||||||
print_cmd ("req:%u '%s'%s%s%s%s%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
|
/* g_message() alone does not warn about invalid format. Add a dummy printf() statement to
|
||||||
(_request)->request_id, \
|
* get a compiler warning about wrong format. */ \
|
||||||
(_request)->action, \
|
printf (__VA_ARGS__); \
|
||||||
(_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__); \
|
|
||||||
} \
|
} \
|
||||||
|
print_cmd (__VA_ARGS__); \
|
||||||
} G_STMT_END
|
} G_STMT_END
|
||||||
|
|
||||||
static gboolean
|
#define __LOG_print_R(print_cmd, _request, ...) \
|
||||||
_LOG_R_D_enabled (const Request *request)
|
G_STMT_START { \
|
||||||
{
|
__LOG_print (print_cmd, \
|
||||||
return request->debug;
|
"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_print_S(print_cmd, _request, _script, ...) \
|
||||||
#define _LOG_R_I(_request, ...) _LOG(_request, NULL, TRUE, g_info, __VA_ARGS__)
|
G_STMT_START { \
|
||||||
#define _LOG_R_W(_request, ...) _LOG(_request, NULL, TRUE, g_warning, __VA_ARGS__)
|
__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_X_(enabled_cmd, print_cmd, ...) \
|
||||||
#define _LOG_S_I(_script, ...) _LOG(NULL, _script, TRUE, g_info, __VA_ARGS__)
|
G_STMT_START { \
|
||||||
#define _LOG_S_W(_script, ...) _LOG(NULL, _script, TRUE, g_warning, __VA_ARGS__)
|
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
|
static gboolean
|
||||||
quit_timeout_cb (gpointer user_data)
|
quit_timeout_cb (gpointer user_data)
|
||||||
{
|
{
|
||||||
g_main_loop_quit (loop);
|
gl.quit_id = 0;
|
||||||
return FALSE;
|
g_main_loop_quit (gl.loop);
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
quit_timeout_reschedule (void)
|
quit_timeout_reschedule (void)
|
||||||
{
|
{
|
||||||
if (!persist) {
|
if (!gl.persist) {
|
||||||
nm_clear_g_source (&quit_id);
|
nm_clear_g_source (&gl.quit_id);
|
||||||
quit_id = g_timeout_add_seconds (10, quit_timeout_cb, NULL);
|
gl.quit_id = g_timeout_add_seconds (10, quit_timeout_cb, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* next_request:
|
* next_request:
|
||||||
*
|
*
|
||||||
* @h: the handler
|
|
||||||
* @request: (allow-none): the request to set as next. If %NULL, dequeue the next
|
* @request: (allow-none): the request to set as next. If %NULL, dequeue the next
|
||||||
* waiting request. Otherwise, try to set the given request.
|
* waiting request. Otherwise, try to set the given request.
|
||||||
*
|
*
|
||||||
@@ -240,27 +222,27 @@ quit_timeout_reschedule (void)
|
|||||||
* a new request as current.
|
* a new request as current.
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
next_request (Handler *h, Request *request)
|
next_request (Request *request)
|
||||||
{
|
{
|
||||||
if (request) {
|
if (request) {
|
||||||
if (h->current_request) {
|
if (gl.current_request) {
|
||||||
g_queue_push_tail (h->requests_waiting, request);
|
g_queue_push_tail (gl.requests_waiting, request);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* when calling next_request() without explicit @request, we always
|
/* when calling next_request() without explicit @request, we always
|
||||||
* forcefully clear @current_request. That one is certainly
|
* forcefully clear @current_request. That one is certainly
|
||||||
* handled already. */
|
* 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)
|
if (!request)
|
||||||
return FALSE;
|
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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -280,7 +262,6 @@ complete_request (Request *request)
|
|||||||
GVariantBuilder results;
|
GVariantBuilder results;
|
||||||
GVariant *ret;
|
GVariant *ret;
|
||||||
guint i;
|
guint i;
|
||||||
Handler *handler = request->handler;
|
|
||||||
|
|
||||||
nm_assert (request);
|
nm_assert (request);
|
||||||
|
|
||||||
@@ -301,16 +282,16 @@ complete_request (Request *request)
|
|||||||
ret = g_variant_new ("(a(sus))", &results);
|
ret = g_variant_new ("(a(sus))", &results);
|
||||||
g_dbus_method_invocation_return_value (request->context, ret);
|
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)
|
if (gl.current_request == request)
|
||||||
handler->current_request = NULL;
|
gl.current_request = NULL;
|
||||||
|
|
||||||
request_free (request);
|
request_free (request);
|
||||||
|
|
||||||
g_assert_cmpuint (handler->num_requests_pending, >, 0);
|
g_assert_cmpuint (gl.num_requests_pending, >, 0);
|
||||||
if (--handler->num_requests_pending <= 0) {
|
if (--gl.num_requests_pending <= 0) {
|
||||||
nm_assert (!handler->current_request && !g_queue_peek_head (handler->requests_waiting));
|
nm_assert (!gl.current_request && !g_queue_peek_head (gl.requests_waiting));
|
||||||
quit_timeout_reschedule ();
|
quit_timeout_reschedule ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,7 +299,6 @@ complete_request (Request *request)
|
|||||||
static void
|
static void
|
||||||
complete_script (ScriptInfo *script)
|
complete_script (ScriptInfo *script)
|
||||||
{
|
{
|
||||||
Handler *handler;
|
|
||||||
Request *request;
|
Request *request;
|
||||||
gboolean wait = script->wait;
|
gboolean wait = script->wait;
|
||||||
|
|
||||||
@@ -331,9 +311,7 @@ complete_script (ScriptInfo *script)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler = request->handler;
|
nm_assert (!wait || gl.current_request == request);
|
||||||
|
|
||||||
nm_assert (!wait || handler->current_request == request);
|
|
||||||
|
|
||||||
/* Try to complete the request. @request will be possibly free'd,
|
/* Try to complete the request. @request will be possibly free'd,
|
||||||
* making @script and @request a dangling pointer. */
|
* 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
|
* requests. However, if this was the last "no-wait" script and
|
||||||
* there are "wait" scripts ready to run, launch them.
|
* there are "wait" scripts ready to run, launch them.
|
||||||
*/
|
*/
|
||||||
if ( handler->current_request == request
|
if ( gl.current_request == request
|
||||||
&& handler->current_request->num_scripts_nowait == 0) {
|
&& gl.current_request->num_scripts_nowait == 0) {
|
||||||
|
|
||||||
if (dispatch_one_script (handler->current_request))
|
if (dispatch_one_script (gl.current_request))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
complete_request (handler->current_request);
|
complete_request (gl.current_request);
|
||||||
} else
|
} else
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@@ -365,11 +343,11 @@ complete_script (ScriptInfo *script)
|
|||||||
* processed because only requests with "wait" scripts can become
|
* processed because only requests with "wait" scripts can become
|
||||||
* @current_request. As there can only be one "wait" script running
|
* @current_request. As there can only be one "wait" script running
|
||||||
* at any time, it means complete_request() above completed @request. */
|
* 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)) {
|
while (next_request (NULL)) {
|
||||||
request = handler->current_request;
|
request = gl.current_request;
|
||||||
|
|
||||||
if (dispatch_one_script (request))
|
if (dispatch_one_script (request))
|
||||||
return;
|
return;
|
||||||
@@ -418,7 +396,7 @@ script_watch_cb (GPid pid, int status, gpointer user_data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (script->result == DISPATCH_RESULT_SUCCESS) {
|
if (script->result == DISPATCH_RESULT_SUCCESS) {
|
||||||
_LOG_S_D (script, "complete");
|
_LOG_S_T (script, "complete");
|
||||||
} else {
|
} else {
|
||||||
script->result = DISPATCH_RESULT_FAILED;
|
script->result = DISPATCH_RESULT_FAILED;
|
||||||
_LOG_S_W (script, "complete: failed with %s", script->error);
|
_LOG_S_W (script, "complete: failed with %s", script->error);
|
||||||
@@ -533,7 +511,7 @@ script_dispatch (ScriptInfo *script)
|
|||||||
argv[2] = request->action;
|
argv[2] = request->action;
|
||||||
argv[3] = NULL;
|
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)) {
|
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);
|
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
|
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;
|
const char *filename;
|
||||||
gs_free char *dirname = NULL;
|
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);
|
dirname = g_build_filename (base, "dispatcher.d", subdir, NULL);
|
||||||
|
|
||||||
if (!(dir = g_dir_open (dirname, 0, &error))) {
|
if (!(dir = g_dir_open (dirname, 0, &error))) {
|
||||||
g_message ("find-scripts: Failed to open dispatcher directory '%s': %s",
|
if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
|
||||||
dirname, error->message);
|
_LOG_R_W (request, "find-scripts: Failed to open dispatcher directory '%s': %s",
|
||||||
|
dirname, error->message);
|
||||||
|
}
|
||||||
g_error_free (error);
|
g_error_free (error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -615,26 +595,28 @@ _find_scripts (GHashTable *scripts, const char *base, const char *subdir)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GSList *
|
static GSList *
|
||||||
find_scripts (const char *str_action)
|
find_scripts (Request *request)
|
||||||
{
|
{
|
||||||
gs_unref_hashtable GHashTable *scripts = NULL;
|
gs_unref_hashtable GHashTable *scripts = NULL;
|
||||||
GSList *script_list = NULL;
|
GSList *script_list = NULL;
|
||||||
GHashTableIter iter;
|
GHashTableIter iter;
|
||||||
const char *subdir = NULL;
|
const char *subdir;
|
||||||
char *path;
|
char *path;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
||||||
if ( strcmp (str_action, NMD_ACTION_PRE_UP) == 0
|
if (NM_IN_STRSET (request->action, NMD_ACTION_PRE_UP,
|
||||||
|| strcmp (str_action, NMD_ACTION_VPN_PRE_UP) == 0)
|
NMD_ACTION_VPN_PRE_UP))
|
||||||
subdir = "pre-up.d";
|
subdir = "pre-up.d";
|
||||||
else if ( strcmp (str_action, NMD_ACTION_PRE_DOWN) == 0
|
else if (NM_IN_STRSET (request->action, NMD_ACTION_PRE_DOWN,
|
||||||
|| strcmp (str_action, NMD_ACTION_VPN_PRE_DOWN) == 0)
|
NMD_ACTION_VPN_PRE_DOWN))
|
||||||
subdir = "pre-down.d";
|
subdir = "pre-down.d";
|
||||||
|
else
|
||||||
|
subdir = NULL;
|
||||||
|
|
||||||
scripts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
scripts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||||
|
|
||||||
_find_scripts (scripts, NMLIBDIR, subdir);
|
_find_scripts (request, scripts, NMLIBDIR, subdir);
|
||||||
_find_scripts (scripts, NMCONFDIR, subdir);
|
_find_scripts (request, scripts, NMCONFDIR, subdir);
|
||||||
|
|
||||||
g_hash_table_iter_init (&iter, scripts);
|
g_hash_table_iter_init (&iter, scripts);
|
||||||
while (g_hash_table_iter_next (&iter, (gpointer *) &filename, (gpointer *) &path)) {
|
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);
|
err = stat (path, &st);
|
||||||
if (err)
|
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))
|
else if (!S_ISREG (st.st_mode))
|
||||||
; /* silently skip. */
|
; /* silently skip. */
|
||||||
else if (!check_permissions (&st, &err_msg))
|
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 {
|
else {
|
||||||
/* success */
|
/* success */
|
||||||
script_list = g_slist_prepend (script_list, g_strdup (path));
|
script_list = g_slist_prepend (script_list, g_strdup (path));
|
||||||
@@ -695,27 +677,25 @@ script_must_wait (const char *path)
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static void
|
||||||
handle_action (NMDBusDispatcher *dbus_dispatcher,
|
_method_call_action (GDBusMethodInvocation *invocation,
|
||||||
GDBusMethodInvocation *context,
|
GVariant *parameters)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
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 *sorted_scripts = NULL;
|
||||||
GSList *iter;
|
GSList *iter;
|
||||||
Request *request;
|
Request *request;
|
||||||
@@ -723,33 +703,65 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
|
|||||||
guint i, num_nowait = 0;
|
guint i, num_nowait = 0;
|
||||||
const char *error_message = NULL;
|
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 = g_slice_new0 (Request);
|
||||||
request->request_id = ++request_id_counter;
|
request->request_id = ++gl.request_id_counter;
|
||||||
request->handler = h;
|
request->debug = debug || gl.debug;
|
||||||
request->debug = request_debug || debug;
|
request->context = invocation;
|
||||||
request->context = context;
|
request->action = g_strdup (action);
|
||||||
request->action = g_strdup (str_action);
|
|
||||||
|
|
||||||
request->envp = nm_dispatcher_utils_construct_envp (str_action,
|
request->envp = nm_dispatcher_utils_construct_envp (action,
|
||||||
connection_dict,
|
connection,
|
||||||
connection_props,
|
connection_properties,
|
||||||
device_props,
|
device_properties,
|
||||||
device_proxy_props,
|
device_proxy_properties,
|
||||||
device_ip4_props,
|
device_ip4_config,
|
||||||
device_ip6_props,
|
device_ip6_config,
|
||||||
device_dhcp4_props,
|
device_dhcp4_config,
|
||||||
device_dhcp6_props,
|
device_dhcp6_config,
|
||||||
connectivity_state,
|
connectivity_state,
|
||||||
vpn_ip_iface,
|
vpn_ip_iface,
|
||||||
vpn_proxy_props,
|
vpn_proxy_properties,
|
||||||
vpn_ip4_props,
|
vpn_ip4_config,
|
||||||
vpn_ip6_props,
|
vpn_ip6_config,
|
||||||
&request->iface,
|
&request->iface,
|
||||||
&error_message);
|
&error_message);
|
||||||
|
|
||||||
request->scripts = g_ptr_array_new_full (5, script_info_free);
|
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)) {
|
for (iter = sorted_scripts; iter; iter = g_slist_next (iter)) {
|
||||||
ScriptInfo *s;
|
ScriptInfo *s;
|
||||||
|
|
||||||
@@ -761,11 +773,11 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
|
|||||||
}
|
}
|
||||||
g_slist_free (sorted_scripts);
|
g_slist_free (sorted_scripts);
|
||||||
|
|
||||||
_LOG_R_I (request, "new request (%u scripts)", request->scripts->len);
|
_LOG_R_D (request, "new request (%u scripts)", request->scripts->len);
|
||||||
if ( _LOG_R_D_enabled (request)
|
if ( _LOG_R_T_enabled (request)
|
||||||
&& request->envp) {
|
&& request->envp) {
|
||||||
for (p = request->envp; *p; p++)
|
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) {
|
if (error_message || request->scripts->len == 0) {
|
||||||
@@ -774,18 +786,18 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
|
|||||||
if (error_message)
|
if (error_message)
|
||||||
_LOG_R_W (request, "completed: invalid request: %s", error_message);
|
_LOG_R_W (request, "completed: invalid request: %s", error_message);
|
||||||
else
|
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);
|
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->num_scripts_done = request->scripts->len;
|
||||||
request_free (request);
|
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++) {
|
for (i = 0; i < request->scripts->len; i++) {
|
||||||
ScriptInfo *s = g_ptr_array_index (request->scripts, 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.
|
/* The request has at least one wait script.
|
||||||
* Try next_request() to schedule the request for
|
* Try next_request() to schedule the request for
|
||||||
* execution. This either enqueues the request or
|
* execution. This either enqueues the request or
|
||||||
* sets it as h->current_request. */
|
* sets it as gl.current_request. */
|
||||||
if (next_request (h, request)) {
|
if (next_request (request)) {
|
||||||
/* @request is now @current_request. Go ahead and
|
/* @request is now @current_request. Go ahead and
|
||||||
* schedule the first wait script. */
|
* schedule the first wait script. */
|
||||||
if (!dispatch_one_script (request)) {
|
if (!dispatch_one_script (request)) {
|
||||||
@@ -809,7 +821,7 @@ handle_action (NMDBusDispatcher *dbus_dispatcher,
|
|||||||
* request. Try complete_request(). */
|
* request. Try complete_request(). */
|
||||||
complete_request (request);
|
complete_request (request);
|
||||||
|
|
||||||
if (next_request (h, NULL)) {
|
if (next_request (NULL)) {
|
||||||
/* As @request was successfully scheduled as next_request(), there is no
|
/* As @request was successfully scheduled as next_request(), there is no
|
||||||
* other request in queue that can be scheduled afterwards. Assert against
|
* other request in queue that can be scheduled afterwards. Assert against
|
||||||
* that, but call next_request() to clear current_request. */
|
* 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
|
* the request right away (we might have failed to schedule any
|
||||||
* of the scripts). It will be either completed now, or later
|
* of the scripts). It will be either completed now, or later
|
||||||
* when the pending scripts return.
|
* 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
|
* There is no need to handle next_request(), because @request is
|
||||||
* not the current request anyway and does not interfere with requests
|
* not the current request anyway and does not interfere with requests
|
||||||
* that have any "wait" scripts. */
|
* that have any "wait" scripts. */
|
||||||
complete_request (request);
|
complete_request (request);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean ever_acquired_name = FALSE;
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_name_acquired (GDBusConnection *connection,
|
on_name_acquired (GDBusConnection *connection,
|
||||||
const char *name,
|
const char *name,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
ever_acquired_name = TRUE;
|
gl.ever_acquired_name = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -848,22 +856,79 @@ on_name_lost (GDBusConnection *connection,
|
|||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
if (!ever_acquired_name) {
|
if (!gl.ever_acquired_name) {
|
||||||
g_warning ("Could not get the system bus. Make sure the message bus daemon is running!");
|
_LOG_X_W ("Could not get the system bus. Make sure the message bus daemon is running!");
|
||||||
exit (1);
|
gl.exit_with_failure = TRUE;
|
||||||
} else {
|
} else {
|
||||||
g_message ("System bus stopped. Exiting");
|
_LOG_X_I ("System bus stopped. Exiting");
|
||||||
exit (0);
|
|
||||||
}
|
}
|
||||||
} else if (!ever_acquired_name) {
|
} else if (!gl.ever_acquired_name) {
|
||||||
g_warning ("Could not acquire the " NM_DISPATCHER_DBUS_SERVICE " service.");
|
_LOG_X_W ("Could not acquire the " NM_DISPATCHER_DBUS_SERVICE " service.");
|
||||||
exit (1);
|
gl.exit_with_failure = TRUE;
|
||||||
} else {
|
} else
|
||||||
g_message ("Lost the " NM_DISPATCHER_DBUS_SERVICE " name. Exiting");
|
_LOG_X_I ("Lost the " NM_DISPATCHER_DBUS_SERVICE " name. Exiting");
|
||||||
exit (0);
|
|
||||||
}
|
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
|
static void
|
||||||
log_handler (const char *log_domain,
|
log_handler (const char *log_domain,
|
||||||
GLogLevelFlags log_level,
|
GLogLevelFlags log_level,
|
||||||
@@ -918,42 +983,55 @@ signal_handler (gpointer user_data)
|
|||||||
{
|
{
|
||||||
int signo = GPOINTER_TO_INT (user_data);
|
int signo = GPOINTER_TO_INT (user_data);
|
||||||
|
|
||||||
g_message ("Caught signal %d, shutting down...", signo);
|
_LOG_X_I ("Caught signal %d, shutting down...", signo);
|
||||||
g_main_loop_quit (loop);
|
g_main_loop_quit (gl.loop);
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static gboolean
|
||||||
main (int argc, char **argv)
|
parse_command_line (int *p_argc,
|
||||||
|
char ***p_argv,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
GOptionContext *opt_ctx;
|
GOptionContext *opt_ctx;
|
||||||
GError *error = NULL;
|
|
||||||
GDBusConnection *bus;
|
|
||||||
Handler *handler;
|
|
||||||
|
|
||||||
GOptionEntry entries[] = {
|
GOptionEntry entries[] = {
|
||||||
{ "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Output to console rather than syslog", NULL },
|
{ "debug", 0, 0, G_OPTION_ARG_NONE, &gl.debug, "Output to console rather than syslog", NULL },
|
||||||
{ "persist", 0, 0, G_OPTION_ARG_NONE, &persist, "Don't quit after a short timeout", NULL },
|
{ "persist", 0, 0, G_OPTION_ARG_NONE, &gl.persist, "Don't quit after a short timeout", NULL },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
gboolean success;
|
||||||
|
|
||||||
opt_ctx = g_option_context_new (NULL);
|
opt_ctx = g_option_context_new (NULL);
|
||||||
g_option_context_set_summary (opt_ctx, "Executes scripts upon actions by NetworkManager.");
|
g_option_context_set_summary (opt_ctx, "Executes scripts upon actions by NetworkManager.");
|
||||||
g_option_context_add_main_entries (opt_ctx, entries, NULL);
|
g_option_context_add_main_entries (opt_ctx, entries, NULL);
|
||||||
|
|
||||||
if (!g_option_context_parse (opt_ctx, &argc, &argv, &error)) {
|
success = g_option_context_parse (opt_ctx, p_argc, p_argv, error);
|
||||||
g_warning ("Error parsing command line arguments: %s", error->message);
|
|
||||||
g_error_free (error);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_option_context_free (opt_ctx);
|
g_option_context_free (opt_ctx);
|
||||||
|
|
||||||
g_unix_signal_add (SIGTERM, signal_handler, GINT_TO_POINTER (SIGTERM));
|
return success;
|
||||||
g_unix_signal_add (SIGINT, signal_handler, GINT_TO_POINTER (SIGINT));
|
}
|
||||||
|
|
||||||
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")) {
|
if (!g_getenv ("G_MESSAGES_DEBUG")) {
|
||||||
/* we log our regular messages using g_debug() and g_info().
|
/* we log our regular messages using g_debug() and g_info().
|
||||||
* When we redirect glib logging to syslog, there is no problem.
|
* When we redirect glib logging to syslog, there is no problem.
|
||||||
@@ -964,45 +1042,75 @@ main (int argc, char **argv)
|
|||||||
} else
|
} else
|
||||||
logging_setup ();
|
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);
|
gl.dbus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
||||||
if (!bus) {
|
if (!gl.dbus_connection) {
|
||||||
g_warning ("Could not get the system bus (%s). Make sure the message bus daemon is running!",
|
_LOG_X_W ("Could not get the system bus (%s). Make sure the message bus daemon is running!",
|
||||||
error->message);
|
error->message);
|
||||||
g_error_free (error);
|
gl.exit_with_failure = TRUE;
|
||||||
return 1;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
handler = g_object_new (HANDLER_TYPE, NULL);
|
gl.requests_waiting = g_queue_new ();
|
||||||
g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (handler->dbus_dispatcher),
|
|
||||||
bus,
|
dbus_regist_id = g_dbus_connection_register_object (gl.dbus_connection,
|
||||||
NM_DISPATCHER_DBUS_PATH,
|
NM_DISPATCHER_DBUS_PATH,
|
||||||
&error);
|
interface_info,
|
||||||
if (error) {
|
NM_UNCONST_PTR (GDBusInterfaceVTable, &interface_vtable),
|
||||||
g_warning ("Could not export Dispatcher D-Bus interface: %s", error->message);
|
NULL,
|
||||||
g_error_free (error);
|
NULL,
|
||||||
return 1;
|
&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,
|
dbus_own_name_id = g_bus_own_name_on_connection (gl.dbus_connection,
|
||||||
NM_DISPATCHER_DBUS_SERVICE,
|
NM_DISPATCHER_DBUS_SERVICE,
|
||||||
G_BUS_NAME_OWNER_FLAGS_NONE,
|
G_BUS_NAME_OWNER_FLAGS_NONE,
|
||||||
on_name_acquired,
|
on_name_acquired,
|
||||||
on_name_lost,
|
on_name_lost,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
g_object_unref (bus);
|
|
||||||
|
|
||||||
quit_timeout_reschedule ();
|
quit_timeout_reschedule ();
|
||||||
|
|
||||||
g_main_loop_run (loop);
|
g_main_loop_run (gl.loop);
|
||||||
|
|
||||||
g_queue_free (handler->requests_waiting);
|
done:
|
||||||
g_object_unref (handler);
|
|
||||||
|
|
||||||
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 ();
|
logging_shutdown ();
|
||||||
|
|
||||||
return 0;
|
return gl.exit_with_failure ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -7,7 +7,7 @@ incs = [
|
|||||||
|
|
||||||
exe = executable(
|
exe = executable(
|
||||||
test_unit,
|
test_unit,
|
||||||
test_unit + '.c',
|
[ test_unit + '.c' ] + [ nmdbus_dispatcher_sources ],
|
||||||
include_directories: incs,
|
include_directories: incs,
|
||||||
dependencies: libnm_core_dep,
|
dependencies: libnm_core_dep,
|
||||||
c_args: [
|
c_args: [
|
||||||
|
@@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
#include "nm-utils/nm-test-utils.h"
|
#include "nm-utils/nm-test-utils.h"
|
||||||
|
|
||||||
|
#include "nmdbus-dispatcher.h"
|
||||||
|
|
||||||
#define TEST_DIR NM_BUILD_SRCDIR"/dispatcher/tests"
|
#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 ();
|
NMTST_DEFINE ();
|
||||||
|
|
||||||
int
|
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/up_empty_vpn_iface", test_up_empty_vpn_iface);
|
||||||
|
|
||||||
|
g_test_add_func ("/dispatcher/gdbus-codegen", test_gdbus_codegen);
|
||||||
|
|
||||||
return g_test_run ();
|
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
|
* It's useful to check the let the compiler ensure that @value is
|
||||||
* of a certain type. */
|
* of a certain type. */
|
||||||
#define _NM_ENSURE_TYPE(type, value) (_Generic ((value), type: (value)))
|
#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
|
#else
|
||||||
#define _NM_ENSURE_TYPE(type, value) (value)
|
#define _NM_ENSURE_TYPE(type, value) (value)
|
||||||
|
#define _NM_ENSURE_TYPE_CONST(type, value) ((const type) (value))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if _NM_CC_SUPPORT_GENERIC
|
#if _NM_CC_SUPPORT_GENERIC
|
||||||
|
@@ -328,16 +328,18 @@ typedef struct _NMDevicePrivate {
|
|||||||
ActivationHandleData act_handle4; /* for layer2 and IPv4. */
|
ActivationHandleData act_handle4; /* for layer2 and IPv4. */
|
||||||
ActivationHandleData act_handle6;
|
ActivationHandleData act_handle6;
|
||||||
guint recheck_assume_id;
|
guint recheck_assume_id;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
guint call_id;
|
guint call_id;
|
||||||
NMDeviceStateReason available_reason;
|
NMDeviceStateReason available_reason;
|
||||||
NMDeviceStateReason unavailable_reason;
|
NMDeviceStateReason unavailable_reason;
|
||||||
} recheck_available;
|
} recheck_available;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
guint call_id;
|
NMDispatcherCallId *call_id;
|
||||||
NMDeviceState post_state;
|
NMDeviceState post_state;
|
||||||
NMDeviceStateReason post_state_reason;
|
NMDeviceStateReason post_state_reason;
|
||||||
} dispatcher;
|
} dispatcher;
|
||||||
|
|
||||||
/* Link stuff */
|
/* Link stuff */
|
||||||
guint link_connected_id;
|
guint link_connected_id;
|
||||||
@@ -12373,29 +12375,31 @@ nm_device_get_ip6_config (NMDevice *self)
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
dispatcher_cleanup (NMDevice *self)
|
dispatcher_cleanup (NMDevice *self)
|
||||||
{
|
{
|
||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
if (priv->dispatcher.call_id) {
|
if (!priv->dispatcher.call_id)
|
||||||
nm_dispatcher_call_cancel (priv->dispatcher.call_id);
|
return FALSE;
|
||||||
priv->dispatcher.call_id = 0;
|
|
||||||
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
|
nm_dispatcher_call_cancel (g_steal_pointer (&priv->dispatcher.call_id));
|
||||||
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
|
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
|
||||||
}
|
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
NMDevice *self = NM_DEVICE (user_data);
|
||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
g_return_if_fail (call_id == priv->dispatcher.call_id);
|
g_return_if_fail (call_id == priv->dispatcher.call_id);
|
||||||
|
|
||||||
priv->dispatcher.call_id = 0;
|
priv->dispatcher.call_id = NULL;
|
||||||
nm_device_queue_state (self, priv->dispatcher.post_state,
|
nm_device_queue_state (self,
|
||||||
|
priv->dispatcher.post_state,
|
||||||
priv->dispatcher.post_state_reason);
|
priv->dispatcher.post_state_reason);
|
||||||
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
|
priv->dispatcher.post_state = NM_DEVICE_STATE_UNKNOWN;
|
||||||
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
|
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);
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
if (priv->dispatcher.call_id != 0) {
|
if (dispatcher_cleanup (self))
|
||||||
g_warn_if_reached ();
|
nm_assert_not_reached ();
|
||||||
dispatcher_cleanup (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES;
|
priv->dispatcher.post_state = NM_DEVICE_STATE_SECONDARIES;
|
||||||
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
|
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
|
||||||
@@ -14822,7 +14824,7 @@ deactivate_async_ready (NMDevice *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
NMDevice *self = NM_DEVICE (user_data);
|
||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
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;
|
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 = NM_DEVICE_STATE_UNKNOWN;
|
||||||
priv->dispatcher.post_state_reason = NM_DEVICE_STATE_REASON_NONE;
|
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,
|
nm_manager_dbus_set_property_handle,
|
||||||
manager);
|
manager);
|
||||||
|
|
||||||
nm_dispatcher_init ();
|
|
||||||
|
|
||||||
g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);
|
g_signal_connect (manager, NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);
|
||||||
|
|
||||||
if (!nm_manager_start (manager, &error)) {
|
if (!nm_manager_start (manager, &error)) {
|
||||||
|
@@ -44,8 +44,121 @@
|
|||||||
#define _NMLOG_DOMAIN LOGD_DISPATCH
|
#define _NMLOG_DOMAIN LOGD_DISPATCH
|
||||||
#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "dispatcher", __VA_ARGS__)
|
#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "dispatcher", __VA_ARGS__)
|
||||||
|
|
||||||
static GDBusProxy *dispatcher_proxy;
|
#define _NMLOG2_DOMAIN LOGD_DISPATCH
|
||||||
static GHashTable *requests = NULL;
|
#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
|
static void
|
||||||
dump_proxy_to_props (NMProxyConfig *proxy, GVariantBuilder *builder)
|
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);
|
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 *
|
static const char *
|
||||||
dispatch_result_to_string (DispatchResult result)
|
dispatch_result_to_string (DispatchResult result)
|
||||||
{
|
{
|
||||||
@@ -339,63 +419,71 @@ dispatch_result_to_string (DispatchResult result)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
const char *script, *err;
|
||||||
guint32 result;
|
guint32 result;
|
||||||
|
|
||||||
g_return_if_fail (results != NULL);
|
g_variant_get (v_results, "(a(sus))", &results);
|
||||||
|
|
||||||
if (g_variant_iter_n_children (results) == 0) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (g_variant_iter_next (results, "(&su&s)", &script, &result, &err)) {
|
while (g_variant_iter_next (results, "(&su&s)", &script, &result, &err)) {
|
||||||
if (result == DISPATCH_RESULT_SUCCESS) {
|
if (result == DISPATCH_RESULT_SUCCESS) {
|
||||||
_LOGD ("(%u) %s succeeded", request_id, script);
|
_LOG2D (request_id, log_ifname, log_con_uuid, "%s succeeded", script);
|
||||||
} else {
|
} else {
|
||||||
_LOGW ("(%u) %s failed (%s): %s",
|
_LOG2W (request_id,
|
||||||
request_id,
|
log_ifname,
|
||||||
script,
|
log_con_uuid,
|
||||||
dispatch_result_to_string (result),
|
"%s failed (%s): %s",
|
||||||
err);
|
script,
|
||||||
|
dispatch_result_to_string (result),
|
||||||
|
err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
gs_unref_variant GVariant *ret = NULL;
|
||||||
GVariant *ret;
|
gs_free_error GError *error = NULL;
|
||||||
GVariantIter *results;
|
NMDispatcherCallId *call_id = user_data;
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
ret = _nm_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result,
|
nm_assert ((gpointer) source == gl.dbus_connection);
|
||||||
G_VARIANT_TYPE ("(a(sus))"),
|
|
||||||
&error);
|
ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
|
||||||
if (ret) {
|
result,
|
||||||
g_variant_get (ret, "(a(sus))", &results);
|
&error);
|
||||||
dispatcher_results_process (info->request_id, info->action, results);
|
if (!ret) {
|
||||||
g_variant_iter_free (results);
|
|
||||||
g_variant_unref (ret);
|
|
||||||
} else {
|
|
||||||
if (_nm_dbus_error_has_name (error, "org.freedesktop.systemd1.LoadFailed")) {
|
if (_nm_dbus_error_has_name (error, "org.freedesktop.systemd1.LoadFailed")) {
|
||||||
g_dbus_error_strip_remote_error (error);
|
g_dbus_error_strip_remote_error (error);
|
||||||
_LOGW ("(%u) failed to call dispatcher scripts: %s",
|
_LOG3W (call_id, "failed to call dispatcher scripts: %s",
|
||||||
info->request_id, error->message);
|
error->message);
|
||||||
} else {
|
} else {
|
||||||
_LOGD ("(%u) failed to call dispatcher scripts: %s",
|
_LOG3D (call_id, "failed to call dispatcher scripts: %s",
|
||||||
info->request_id, error->message);
|
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)
|
g_hash_table_remove (gl.requests, call_id);
|
||||||
info->callback (info->request_id, info->user_data);
|
|
||||||
|
|
||||||
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[] = {
|
static const char *action_table[] = {
|
||||||
@@ -416,8 +504,9 @@ static const char *action_table[] = {
|
|||||||
static const char *
|
static const char *
|
||||||
action_to_string (NMDispatcherAction action)
|
action_to_string (NMDispatcherAction action)
|
||||||
{
|
{
|
||||||
g_assert ((gsize) action < G_N_ELEMENTS (action_table));
|
if (G_UNLIKELY ((gsize) action >= G_N_ELEMENTS (action_table)))
|
||||||
return action_table[action];
|
g_return_val_if_reached (NULL);
|
||||||
|
return action_table[(gsize) action];
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
@@ -434,7 +523,7 @@ _dispatcher_call (NMDispatcherAction action,
|
|||||||
NMIP6Config *vpn_ip6_config,
|
NMIP6Config *vpn_ip6_config,
|
||||||
NMDispatcherFunc callback,
|
NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id)
|
NMDispatcherCallId **out_call_id)
|
||||||
{
|
{
|
||||||
GVariant *connection_dict;
|
GVariant *connection_dict;
|
||||||
GVariantBuilder connection_props;
|
GVariantBuilder connection_props;
|
||||||
@@ -442,47 +531,57 @@ _dispatcher_call (NMDispatcherAction action,
|
|||||||
GVariantBuilder device_proxy_props;
|
GVariantBuilder device_proxy_props;
|
||||||
GVariantBuilder device_ip4_props;
|
GVariantBuilder device_ip4_props;
|
||||||
GVariantBuilder device_ip6_props;
|
GVariantBuilder device_ip6_props;
|
||||||
GVariant *device_dhcp4_props = NULL;
|
gs_unref_variant GVariant *parameters_floating = NULL;
|
||||||
GVariant *device_dhcp6_props = NULL;
|
gs_unref_variant GVariant *device_dhcp4_props = NULL;
|
||||||
|
gs_unref_variant GVariant *device_dhcp6_props = NULL;
|
||||||
GVariantBuilder vpn_proxy_props;
|
GVariantBuilder vpn_proxy_props;
|
||||||
GVariantBuilder vpn_ip4_props;
|
GVariantBuilder vpn_ip4_props;
|
||||||
GVariantBuilder vpn_ip6_props;
|
GVariantBuilder vpn_ip6_props;
|
||||||
DispatchInfo *info = NULL;
|
NMDispatcherCallId *call_id;
|
||||||
gboolean success = FALSE;
|
guint request_id;
|
||||||
GError *error = NULL;
|
|
||||||
static guint request_counter = 0;
|
|
||||||
guint reqid = ++request_counter;
|
|
||||||
const char *connectivity_state_string = "UNKNOWN";
|
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;
|
return FALSE;
|
||||||
|
|
||||||
/* Wrapping protection */
|
log_ifname = device ? nm_device_get_iface (device) : NULL;
|
||||||
if (G_UNLIKELY (!reqid))
|
log_con_uuid = settings_connection ? nm_settings_connection_get_uuid (settings_connection) : NULL;
|
||||||
reqid = ++request_counter;
|
|
||||||
|
|
||||||
g_assert (!blocking || (!callback && !user_data));
|
request_id = ++gl.request_id_counter;
|
||||||
|
if (G_UNLIKELY (!request_id))
|
||||||
_ensure_requests ();
|
request_id = ++gl.request_id_counter;
|
||||||
|
|
||||||
/* All actions except 'hostname' and 'connectivity-change' require a device */
|
/* All actions except 'hostname' and 'connectivity-change' require a device */
|
||||||
if ( action == NM_DISPATCHER_ACTION_HOSTNAME
|
if ( action == NM_DISPATCHER_ACTION_HOSTNAME
|
||||||
|| action == NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE) {
|
|| action == NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE) {
|
||||||
_LOGD ("(%u) dispatching action '%s'%s",
|
_LOG2D (request_id,
|
||||||
reqid, action_to_string (action),
|
log_ifname,
|
||||||
blocking
|
log_con_uuid,
|
||||||
|
"dispatching action '%s'%s",
|
||||||
|
action_to_string (action),
|
||||||
|
blocking
|
||||||
? " (blocking)"
|
? " (blocking)"
|
||||||
: (callback ? " (with callback)" : ""));
|
: (callback ? " (with callback)" : ""));
|
||||||
} else {
|
} else {
|
||||||
g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
|
g_return_val_if_fail (NM_IS_DEVICE (device), FALSE);
|
||||||
|
|
||||||
_LOGD ("(%u) (%s) dispatching action '%s'%s",
|
_LOG2D (request_id,
|
||||||
reqid,
|
log_ifname,
|
||||||
vpn_iface ?: nm_device_get_iface(device),
|
log_con_uuid,
|
||||||
action_to_string (action),
|
"(%s) dispatching action '%s'%s",
|
||||||
blocking
|
vpn_iface ?: nm_device_get_iface (device),
|
||||||
? " (blocking)"
|
action_to_string (action),
|
||||||
: (callback ? " (with callback)" : ""));
|
blocking
|
||||||
|
? " (blocking)"
|
||||||
|
: (callback ? " (with callback)" : ""));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (applied_connection)
|
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);
|
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 */
|
/* Send the action to the dispatcher */
|
||||||
if (blocking) {
|
if (blocking) {
|
||||||
GVariant *ret;
|
gs_unref_variant GVariant *ret = NULL;
|
||||||
GVariantIter *results;
|
gs_free_error GError *error = NULL;
|
||||||
|
|
||||||
ret = _nm_dbus_proxy_call_sync (dispatcher_proxy, "Action",
|
ret = g_dbus_connection_call_sync (gl.dbus_connection,
|
||||||
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)",
|
NM_DISPATCHER_DBUS_SERVICE,
|
||||||
action_to_string (action),
|
NM_DISPATCHER_DBUS_PATH,
|
||||||
connection_dict,
|
NM_DISPATCHER_DBUS_INTERFACE,
|
||||||
&connection_props,
|
"Action",
|
||||||
&device_props,
|
g_steal_pointer (¶meters_floating),
|
||||||
&device_proxy_props,
|
G_VARIANT_TYPE ("(a(sus))"),
|
||||||
&device_ip4_props,
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
&device_ip6_props,
|
CALL_TIMEOUT,
|
||||||
device_dhcp4_props,
|
NULL,
|
||||||
device_dhcp6_props,
|
&error);
|
||||||
connectivity_state_string,
|
if (!ret) {
|
||||||
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 {
|
|
||||||
g_dbus_error_strip_remote_error (error);
|
g_dbus_error_strip_remote_error (error);
|
||||||
_LOGW ("(%u) failed: %s", reqid, error->message);
|
_LOG2W (request_id, log_ifname, log_con_uuid, "failed: %s", error->message);
|
||||||
g_clear_error (&error);
|
return FALSE;
|
||||||
success = FALSE;
|
|
||||||
}
|
}
|
||||||
} else {
|
dispatcher_results_process (request_id, log_ifname, log_con_uuid, ret);
|
||||||
info = g_malloc0 (sizeof (*info));
|
return TRUE;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_variant_unref (device_dhcp4_props);
|
call_id = dispatcher_call_id_new (request_id,
|
||||||
g_variant_unref (device_dhcp6_props);
|
action,
|
||||||
|
callback,
|
||||||
|
user_data,
|
||||||
|
log_ifname,
|
||||||
|
log_con_uuid);
|
||||||
|
|
||||||
if (success && info) {
|
g_dbus_connection_call (gl.dbus_connection,
|
||||||
/* Track the request in case of cancelation */
|
NM_DISPATCHER_DBUS_SERVICE,
|
||||||
g_hash_table_insert (requests, GUINT_TO_POINTER (info->request_id), info);
|
NM_DISPATCHER_DBUS_PATH,
|
||||||
if (out_call_id)
|
NM_DISPATCHER_DBUS_INTERFACE,
|
||||||
*out_call_id = info->request_id;
|
"Action",
|
||||||
} else if (out_call_id)
|
g_steal_pointer (¶meters_floating),
|
||||||
*out_call_id = 0;
|
G_VARIANT_TYPE ("(a(sus))"),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
return success;
|
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
|
gboolean
|
||||||
nm_dispatcher_call_hostname (NMDispatcherFunc callback,
|
nm_dispatcher_call_hostname (NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id)
|
NMDispatcherCallId **out_call_id)
|
||||||
{
|
{
|
||||||
return _dispatcher_call (NM_DISPATCHER_ACTION_HOSTNAME, FALSE,
|
return _dispatcher_call (NM_DISPATCHER_ACTION_HOSTNAME, FALSE,
|
||||||
NULL, NULL, NULL, FALSE,
|
NULL, NULL, NULL, FALSE,
|
||||||
@@ -673,7 +754,7 @@ nm_dispatcher_call_device (NMDispatcherAction action,
|
|||||||
NMActRequest *act_request,
|
NMActRequest *act_request,
|
||||||
NMDispatcherFunc callback,
|
NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id)
|
NMDispatcherCallId **out_call_id)
|
||||||
{
|
{
|
||||||
nm_assert (NM_IS_DEVICE (device));
|
nm_assert (NM_IS_DEVICE (device));
|
||||||
if (!act_request) {
|
if (!act_request) {
|
||||||
@@ -757,7 +838,7 @@ nm_dispatcher_call_vpn (NMDispatcherAction action,
|
|||||||
NMIP6Config *vpn_ip6_config,
|
NMIP6Config *vpn_ip6_config,
|
||||||
NMDispatcherFunc callback,
|
NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id)
|
NMDispatcherCallId **out_call_id)
|
||||||
{
|
{
|
||||||
return _dispatcher_call (action, FALSE,
|
return _dispatcher_call (action, FALSE,
|
||||||
parent_device,
|
parent_device,
|
||||||
@@ -821,7 +902,7 @@ gboolean
|
|||||||
nm_dispatcher_call_connectivity (NMConnectivityState connectivity_state,
|
nm_dispatcher_call_connectivity (NMConnectivityState connectivity_state,
|
||||||
NMDispatcherFunc callback,
|
NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id)
|
NMDispatcherCallId **out_call_id)
|
||||||
{
|
{
|
||||||
return _dispatcher_call (NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE, FALSE,
|
return _dispatcher_call (NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE, FALSE,
|
||||||
NULL, NULL, NULL, FALSE,
|
NULL, NULL, NULL, FALSE,
|
||||||
@@ -831,40 +912,16 @@ nm_dispatcher_call_connectivity (NMConnectivityState connectivity_state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_dispatcher_call_cancel (guint call_id)
|
nm_dispatcher_call_cancel (NMDispatcherCallId *call_id)
|
||||||
{
|
{
|
||||||
DispatchInfo *info;
|
if ( !call_id
|
||||||
|
|| g_hash_table_lookup (gl.requests, call_id) != call_id
|
||||||
_ensure_requests ();
|
|| !call_id->callback)
|
||||||
|
g_return_if_reached ();
|
||||||
|
|
||||||
/* Canceling just means the callback doesn't get called, so set the
|
/* Canceling just means the callback doesn't get called, so set the
|
||||||
* DispatcherInfo's callback to NULL.
|
* DispatcherInfo's callback to NULL.
|
||||||
*/
|
*/
|
||||||
info = g_hash_table_lookup (requests, GUINT_TO_POINTER (call_id));
|
_LOG3D (call_id, "cancelling dispatcher callback action");
|
||||||
g_return_if_fail (info);
|
call_id->callback = NULL;
|
||||||
|
|
||||||
if (info && info->callback) {
|
|
||||||
_LOGD ("(%u) cancelling dispatcher callback action", call_id);
|
|
||||||
info->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
|
NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE
|
||||||
} NMDispatcherAction;
|
} 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,
|
gboolean nm_dispatcher_call_hostname (NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id);
|
NMDispatcherCallId **out_call_id);
|
||||||
|
|
||||||
gboolean nm_dispatcher_call_device (NMDispatcherAction action,
|
gboolean nm_dispatcher_call_device (NMDispatcherAction action,
|
||||||
NMDevice *device,
|
NMDevice *device,
|
||||||
NMActRequest *act_request,
|
NMActRequest *act_request,
|
||||||
NMDispatcherFunc callback,
|
NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id);
|
NMDispatcherCallId **out_call_id);
|
||||||
|
|
||||||
gboolean nm_dispatcher_call_device_sync (NMDispatcherAction action,
|
gboolean nm_dispatcher_call_device_sync (NMDispatcherAction action,
|
||||||
NMDevice *device,
|
NMDevice *device,
|
||||||
@@ -66,7 +68,7 @@ gboolean nm_dispatcher_call_vpn (NMDispatcherAction action,
|
|||||||
NMIP6Config *vpn_ip6_config,
|
NMIP6Config *vpn_ip6_config,
|
||||||
NMDispatcherFunc callback,
|
NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id);
|
NMDispatcherCallId **out_call_id);
|
||||||
|
|
||||||
gboolean nm_dispatcher_call_vpn_sync (NMDispatcherAction action,
|
gboolean nm_dispatcher_call_vpn_sync (NMDispatcherAction action,
|
||||||
NMSettingsConnection *settings_connection,
|
NMSettingsConnection *settings_connection,
|
||||||
@@ -80,10 +82,8 @@ gboolean nm_dispatcher_call_vpn_sync (NMDispatcherAction action,
|
|||||||
gboolean nm_dispatcher_call_connectivity (NMConnectivityState state,
|
gboolean nm_dispatcher_call_connectivity (NMConnectivityState state,
|
||||||
NMDispatcherFunc callback,
|
NMDispatcherFunc callback,
|
||||||
gpointer user_data,
|
gpointer user_data,
|
||||||
guint *out_call_id);
|
NMDispatcherCallId **out_call_id);
|
||||||
|
|
||||||
void nm_dispatcher_call_cancel (guint call_id);
|
void nm_dispatcher_call_cancel (NMDispatcherCallId *call_id);
|
||||||
|
|
||||||
void nm_dispatcher_init (void);
|
|
||||||
|
|
||||||
#endif /* __NM_DISPATCHER_H__ */
|
#endif /* __NM_DISPATCHER_H__ */
|
||||||
|
@@ -103,7 +103,7 @@ typedef struct {
|
|||||||
char *username;
|
char *username;
|
||||||
|
|
||||||
VpnState vpn_state;
|
VpnState vpn_state;
|
||||||
guint dispatcher_id;
|
NMDispatcherCallId *dispatcher_id;
|
||||||
NMActiveConnectionStateReason failure_reason;
|
NMActiveConnectionStateReason failure_reason;
|
||||||
|
|
||||||
NMVpnServiceState service_state;
|
NMVpnServiceState service_state;
|
||||||
@@ -418,22 +418,28 @@ vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
NMVpnConnection *self = NM_VPN_CONNECTION (user_data);
|
||||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
|
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);
|
_set_vpn_state (self, STATE_DISCONNECTED, NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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);
|
NMVpnConnection *self = NM_VPN_CONNECTION (user_data);
|
||||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
|
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);
|
_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);
|
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
|
||||||
|
|
||||||
if (priv->dispatcher_id) {
|
if (priv->dispatcher_id)
|
||||||
nm_dispatcher_call_cancel (priv->dispatcher_id);
|
nm_dispatcher_call_cancel (g_steal_pointer (&priv->dispatcher_id));
|
||||||
priv->dispatcher_id = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Reference in New Issue
Block a user