dispatcher: reject new requests after releasing name

After we released the well-known name (or if we failed to ever request
it), we must exit as fast as possible, so that a new instance can
be started to serve new requests.

At that point, reject new requests because they are targeted against the
unique name, which they should not do (when talking to a D-Bus activated
service that exits on idle, it's important to talk to the well-known
name).

Also, if we receive SIGTERM, start releasing the name. We are told to
shut down, and must do so in a timely manner. Again, new requests shall
not be served by this instance.
This commit is contained in:
Thomas Haller 2021-08-04 11:33:46 +02:00
parent 9f0984c63b
commit 412b5b4fa7
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728

View file

@ -47,6 +47,8 @@ static struct {
bool name_requested;
bool reject_new_requests;
bool exit_with_failure;
bool shutdown_timeout;
@ -886,6 +888,13 @@ _method_call(GDBusConnection * connection,
GDBusMethodInvocation *invocation,
gpointer user_data)
{
if (gl.reject_new_requests) {
g_dbus_method_invocation_return_error(invocation,
G_DBUS_ERROR,
G_DBUS_ERROR_NO_SERVER,
"Server is exiting");
return;
}
if (nm_streq(interface_name, NM_DISPATCHER_DBUS_INTERFACE)) {
if (nm_streq(method_name, "Action")) {
_method_call_action(invocation, parameters);
@ -1060,14 +1069,60 @@ signal_handler(gpointer user_data)
return G_SOURCE_CONTINUE;
}
/*****************************************************************************/
static void
_bus_release_name_cb(GObject *source, GAsyncResult *result, gpointer user_data)
{
nm_assert(gl.num_requests_pending > 0);
gl.reject_new_requests = TRUE;
gl.num_requests_pending--;
g_main_context_wakeup(NULL);
}
static gboolean
_bus_release_name(void)
{
int r;
/* We already requested a name. To exit-on-idle without race, we need to dance.
* See https://lists.freedesktop.org/archives/dbus/2015-May/016671.html . */
if (!gl.name_requested)
return FALSE;
gl.name_requested = FALSE;
gl.shutdown_quitting = TRUE;
_LOG_X_T("shutdown: release-name");
/* we create a fake pending request. */
gl.num_requests_pending++;
nm_clear_g_source_inst(&gl.quit_source);
r = nm_sd_notify("STOPPING=1");
if (r < 0)
_LOG_X_W("shutdown: sd_notifiy(STOPPING=1) failed: %s", nm_strerror_native(-r));
else
_LOG_X_T("shutdown: sd_notifiy(STOPPING=1) succeeded");
g_dbus_connection_call(gl.dbus_connection,
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"ReleaseName",
g_variant_new("(s)", NM_DISPATCHER_DBUS_SERVICE),
G_VARIANT_TYPE("(u)"),
G_DBUS_CALL_FLAGS_NONE,
10000,
NULL,
_bus_release_name_cb,
NULL);
return TRUE;
}
/*****************************************************************************/
static gboolean
parse_command_line(int *p_argc, char ***p_argv, GError **error)
{
@ -1173,49 +1228,20 @@ main(int argc, char **argv)
if (!g_cancellable_is_cancelled(gl.quit_cancellable))
gl.exit_with_failure = TRUE;
gl.shutdown_quitting = TRUE;
if (!gl.name_requested)
gl.reject_new_requests = TRUE;
}
while (TRUE) {
if (gl.shutdown_quitting)
_bus_release_name();
if (gl.num_requests_pending > 0) {
/* while we have requests pending, we cannot stop processing them... */
} else if (gl.shutdown_timeout || gl.shutdown_quitting) {
if (gl.name_requested) {
int r;
/* We already requested a name. To exit-on-idle without race, we need to dance.
* See https://lists.freedesktop.org/archives/dbus/2015-May/016671.html . */
gl.name_requested = FALSE;
gl.shutdown_quitting = TRUE;
_LOG_X_T("shutdown: release-name");
/* we create a fake pending request. */
gl.num_requests_pending++;
nm_clear_g_source_inst(&gl.quit_source);
r = nm_sd_notify("STOPPING=1");
if (r < 0)
_LOG_X_W("shutdown: sd_notifiy(STOPPING=1) failed: %s", nm_strerror_native(-r));
else
_LOG_X_T("shutdown: sd_notifiy(STOPPING=1) succeeded");
g_dbus_connection_call(gl.dbus_connection,
DBUS_SERVICE_DBUS,
DBUS_PATH_DBUS,
DBUS_INTERFACE_DBUS,
"ReleaseName",
g_variant_new("(s)", NM_DISPATCHER_DBUS_SERVICE),
G_VARIANT_TYPE("(u)"),
G_DBUS_CALL_FLAGS_NONE,
10000,
NULL,
_bus_release_name_cb,
NULL);
continue;
}
break;
if (!_bus_release_name())
break;
}
g_main_context_iteration(NULL, TRUE);