mirror of
https://github.com/morgan9e/grd
synced 2026-04-14 00:14:18 +09:00
1249 lines
38 KiB
C
1249 lines
38 KiB
C
/*
|
|
* Copyright (C) 2015 Red Hat Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*
|
|
* Written by:
|
|
* Jonas Ådahl <jadahl@gmail.com>
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "grd-daemon.h"
|
|
|
|
#include <gio/gio.h>
|
|
#include <glib-unix.h>
|
|
#include <glib/gi18n.h>
|
|
#include <glib/gstdio.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "grd-context.h"
|
|
#include "grd-daemon-user.h"
|
|
#include "grd-dbus-mutter-remote-desktop.h"
|
|
#include "grd-dbus-remote-desktop.h"
|
|
#include "grd-private.h"
|
|
#include "grd-rdp-server.h"
|
|
#include "grd-settings-headless.h"
|
|
#include "grd-settings-system.h"
|
|
#include "grd-settings-user.h"
|
|
#include "grd-types.h"
|
|
#include "grd-vnc-server.h"
|
|
|
|
#ifdef HAVE_LIBSYSTEMD
|
|
#include "grd-daemon-handover.h"
|
|
#include "grd-daemon-system.h"
|
|
#endif /* HAVE_LIBSYSTEMD */
|
|
|
|
#define RDP_SERVER_RESTART_DELAY_MS 3000
|
|
|
|
#define DEFAULT_MAX_PARALLEL_CONNECTIONS 10
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
|
|
PROP_CONTEXT,
|
|
};
|
|
|
|
enum
|
|
{
|
|
MUTTER_PROXY_ACQUIRED,
|
|
RDP_SERVER_STARTED,
|
|
RDP_SERVER_STOPPED,
|
|
|
|
N_SIGNALS,
|
|
};
|
|
|
|
static guint signals[N_SIGNALS];
|
|
|
|
typedef struct _GrdDaemonPrivate
|
|
{
|
|
GSource *sigint_source;
|
|
GSource *sigterm_source;
|
|
|
|
GCancellable *cancellable;
|
|
guint mutter_remote_desktop_watch_name_id;
|
|
guint mutter_screen_cast_watch_name_id;
|
|
|
|
GrdContext *context;
|
|
|
|
GDBusConnection *connection;
|
|
GrdDBusRemoteDesktopOrgGnomeRemoteDesktop *remote_desktop_interface;
|
|
|
|
#ifdef HAVE_RDP
|
|
GrdRdpServer *rdp_server;
|
|
unsigned int restart_rdp_server_source_id;
|
|
GrdDBusRemoteDesktopRdpServer *other_rdp_server_iface;
|
|
unsigned int other_rdp_server_watch_name_id;
|
|
#endif
|
|
#ifdef HAVE_VNC
|
|
GrdVncServer *vnc_server;
|
|
#endif
|
|
} GrdDaemonPrivate;
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (GrdDaemon, grd_daemon, G_TYPE_APPLICATION)
|
|
|
|
#define QUOTE1(a) #a
|
|
#define QUOTE(a) QUOTE1(a)
|
|
|
|
#ifdef HAVE_RDP
|
|
static void maybe_start_rdp_server (GrdDaemon *daemon);
|
|
#endif
|
|
|
|
static const GDBusErrorEntry grd_dbus_error_entries[] =
|
|
{
|
|
{ GRD_DBUS_ERROR_NO_HANDOVER, "org.gnome.RemoteDesktop.Error.NoHandover" },
|
|
};
|
|
|
|
GQuark
|
|
grd_dbus_error_quark (void)
|
|
{
|
|
static gsize quark = 0;
|
|
|
|
g_dbus_error_register_error_domain ("grd-dbus-error-quark",
|
|
&quark,
|
|
grd_dbus_error_entries,
|
|
G_N_ELEMENTS (grd_dbus_error_entries));
|
|
return (GQuark) quark;
|
|
}
|
|
|
|
GCancellable *
|
|
grd_daemon_get_cancellable (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
return priv->cancellable;
|
|
}
|
|
|
|
GrdContext *
|
|
grd_daemon_get_context (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
return priv->context;
|
|
}
|
|
|
|
#ifdef HAVE_RDP
|
|
GrdRdpServer *
|
|
grd_daemon_get_rdp_server (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
return priv->rdp_server;
|
|
}
|
|
#endif /* HAVE_RDP */
|
|
|
|
static void
|
|
export_remote_desktop_interface (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdRuntimeMode runtime_mode = grd_context_get_runtime_mode (priv->context);
|
|
|
|
priv->remote_desktop_interface =
|
|
grd_dbus_remote_desktop_org_gnome_remote_desktop_skeleton_new ();
|
|
|
|
switch (runtime_mode)
|
|
{
|
|
case GRD_RUNTIME_MODE_SCREEN_SHARE:
|
|
grd_dbus_remote_desktop_org_gnome_remote_desktop_set_runtime_mode (
|
|
priv->remote_desktop_interface, "screen-share");
|
|
break;
|
|
case GRD_RUNTIME_MODE_HEADLESS:
|
|
grd_dbus_remote_desktop_org_gnome_remote_desktop_set_runtime_mode (
|
|
priv->remote_desktop_interface, "headless");
|
|
break;
|
|
case GRD_RUNTIME_MODE_SYSTEM:
|
|
grd_dbus_remote_desktop_org_gnome_remote_desktop_set_runtime_mode (
|
|
priv->remote_desktop_interface, "system");
|
|
break;
|
|
case GRD_RUNTIME_MODE_HANDOVER:
|
|
grd_dbus_remote_desktop_org_gnome_remote_desktop_set_runtime_mode (
|
|
priv->remote_desktop_interface, "handover");
|
|
break;
|
|
}
|
|
|
|
g_dbus_interface_skeleton_export (
|
|
G_DBUS_INTERFACE_SKELETON (priv->remote_desktop_interface),
|
|
priv->connection,
|
|
REMOTE_DESKTOP_OBJECT_PATH,
|
|
NULL);
|
|
}
|
|
|
|
static void
|
|
unexport_remote_desktop_interface (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
g_dbus_interface_skeleton_unexport (
|
|
G_DBUS_INTERFACE_SKELETON (priv->remote_desktop_interface));
|
|
|
|
g_clear_object (&priv->remote_desktop_interface);
|
|
}
|
|
|
|
#ifdef HAVE_RDP
|
|
static void
|
|
export_rdp_server_interface (GrdDaemon *daemon)
|
|
{
|
|
GrdDBusRemoteDesktopRdpServer *rdp_server_interface;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdSettings *settings = grd_context_get_settings (priv->context);
|
|
|
|
rdp_server_interface =
|
|
grd_dbus_remote_desktop_rdp_server_skeleton_new ();
|
|
|
|
grd_dbus_remote_desktop_rdp_server_set_enabled (rdp_server_interface, FALSE);
|
|
grd_dbus_remote_desktop_rdp_server_set_port (rdp_server_interface, -1);
|
|
g_object_bind_property (settings, "rdp-negotiate-port",
|
|
rdp_server_interface, "negotiate-port",
|
|
G_BINDING_SYNC_CREATE);
|
|
g_object_bind_property (settings, "rdp-server-cert-path",
|
|
rdp_server_interface, "tls-cert",
|
|
G_BINDING_SYNC_CREATE);
|
|
g_object_bind_property (settings, "rdp-server-fingerprint",
|
|
rdp_server_interface, "tls-fingerprint",
|
|
G_BINDING_SYNC_CREATE);
|
|
g_object_bind_property (settings, "rdp-server-key-path",
|
|
rdp_server_interface, "tls-key",
|
|
G_BINDING_SYNC_CREATE);
|
|
g_object_bind_property (settings, "rdp-auth-methods",
|
|
rdp_server_interface, "auth-methods",
|
|
G_BINDING_SYNC_CREATE);
|
|
g_object_bind_property (settings, "rdp-kerberos-keytab",
|
|
rdp_server_interface, "kerberos-keytab",
|
|
G_BINDING_SYNC_CREATE);
|
|
g_object_bind_property (settings, "rdp-view-only",
|
|
rdp_server_interface, "view-only",
|
|
G_BINDING_SYNC_CREATE);
|
|
|
|
g_dbus_interface_skeleton_export (
|
|
G_DBUS_INTERFACE_SKELETON (rdp_server_interface),
|
|
priv->connection,
|
|
GRD_RDP_SERVER_OBJECT_PATH,
|
|
NULL);
|
|
|
|
grd_context_set_rdp_server_interface (priv->context, rdp_server_interface);
|
|
}
|
|
|
|
static void
|
|
unexport_rdp_server_interface (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdDBusRemoteDesktopRdpServer *rdp_server_interface =
|
|
grd_context_get_rdp_server_interface (priv->context);
|
|
|
|
g_dbus_interface_skeleton_unexport (
|
|
G_DBUS_INTERFACE_SKELETON (rdp_server_interface));
|
|
|
|
grd_context_set_rdp_server_interface (priv->context, NULL);
|
|
}
|
|
|
|
static void
|
|
start_rdp_server_when_ready (GrdDaemon *daemon,
|
|
gboolean should_start_when_ready)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdSettings *settings = grd_context_get_settings (priv->context);
|
|
|
|
g_signal_handlers_disconnect_by_func (G_OBJECT (settings),
|
|
G_CALLBACK (maybe_start_rdp_server),
|
|
daemon);
|
|
|
|
if (!should_start_when_ready)
|
|
return;
|
|
|
|
g_signal_connect_object (G_OBJECT (settings),
|
|
"notify::rdp-server-cert",
|
|
G_CALLBACK (maybe_start_rdp_server),
|
|
daemon, G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (G_OBJECT (settings),
|
|
"notify::rdp-server-key",
|
|
G_CALLBACK (maybe_start_rdp_server),
|
|
daemon, G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (G_OBJECT (settings),
|
|
"notify::rdp-auth-methods",
|
|
G_CALLBACK (maybe_start_rdp_server),
|
|
daemon, G_CONNECT_SWAPPED);
|
|
g_signal_connect_object (G_OBJECT (settings),
|
|
"notify::rdp-kerberos-keytab",
|
|
G_CALLBACK (maybe_start_rdp_server),
|
|
daemon, G_CONNECT_SWAPPED);
|
|
}
|
|
|
|
static void
|
|
stop_rdp_server (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
start_rdp_server_when_ready (daemon, FALSE);
|
|
|
|
if (!priv->rdp_server)
|
|
return;
|
|
|
|
g_signal_emit (daemon, signals[RDP_SERVER_STOPPED], 0);
|
|
grd_rdp_server_stop (priv->rdp_server);
|
|
g_clear_object (&priv->other_rdp_server_iface);
|
|
g_clear_handle_id (&priv->other_rdp_server_watch_name_id, g_bus_unwatch_name);
|
|
g_clear_object (&priv->rdp_server);
|
|
g_clear_handle_id (&priv->restart_rdp_server_source_id, g_source_remove);
|
|
g_message ("RDP server stopped");
|
|
}
|
|
|
|
static void
|
|
on_rdp_server_binding_failed (GrdRdpServer *rdp_server,
|
|
GrdDaemon *daemon)
|
|
{
|
|
stop_rdp_server (daemon);
|
|
}
|
|
|
|
static void
|
|
on_other_rdp_server_new_connection (GrdDBusRemoteDesktopRdpServer *interface,
|
|
GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
g_assert (priv->rdp_server);
|
|
|
|
grd_rdp_server_stop_sessions (priv->rdp_server);
|
|
}
|
|
|
|
static void
|
|
on_remote_desktop_rdp_server_proxy_acquired (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
g_autoptr (GrdDBusRemoteDesktopRdpServer) proxy = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
proxy = grd_dbus_remote_desktop_rdp_server_proxy_new_for_bus_finish (result,
|
|
&error);
|
|
if (!proxy)
|
|
{
|
|
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
return;
|
|
|
|
g_warning ("Failed to create remote desktop rdp server proxy: %s",
|
|
error->message);
|
|
return;
|
|
}
|
|
|
|
priv->other_rdp_server_iface = g_steal_pointer (&proxy);
|
|
g_signal_connect (priv->other_rdp_server_iface, "new-connection",
|
|
G_CALLBACK (on_other_rdp_server_new_connection), daemon);
|
|
}
|
|
|
|
static void
|
|
on_remote_desktop_rdp_server_name_appeared (GDBusConnection *connection,
|
|
const char *name,
|
|
const char *name_owner,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
grd_dbus_remote_desktop_rdp_server_proxy_new (
|
|
connection,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
name,
|
|
GRD_RDP_SERVER_OBJECT_PATH,
|
|
priv->cancellable,
|
|
on_remote_desktop_rdp_server_proxy_acquired,
|
|
daemon);
|
|
}
|
|
|
|
static void
|
|
on_remote_desktop_rdp_server_name_vanished (GDBusConnection *connection,
|
|
const char *name,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
g_clear_object (&priv->other_rdp_server_iface);
|
|
}
|
|
|
|
static void
|
|
connect_to_other_rdp_server (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdRuntimeMode runtime_mode = grd_context_get_runtime_mode (priv->context);
|
|
const char *bus_name;
|
|
|
|
if (priv->other_rdp_server_watch_name_id != 0)
|
|
return;
|
|
|
|
if (runtime_mode == GRD_RUNTIME_MODE_HEADLESS)
|
|
bus_name = GRD_DAEMON_HANDOVER_APPLICATION_ID;
|
|
else if (runtime_mode == GRD_RUNTIME_MODE_HANDOVER)
|
|
bus_name = GRD_DAEMON_HEADLESS_APPLICATION_ID;
|
|
else
|
|
g_assert_not_reached ();
|
|
|
|
priv->other_rdp_server_watch_name_id =
|
|
g_bus_watch_name (G_BUS_TYPE_SESSION,
|
|
bus_name,
|
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
on_remote_desktop_rdp_server_name_appeared,
|
|
on_remote_desktop_rdp_server_name_vanished,
|
|
daemon, NULL);
|
|
}
|
|
|
|
static void
|
|
start_rdp_server (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdRuntimeMode runtime_mode = grd_context_get_runtime_mode (priv->context);
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
g_assert (!priv->rdp_server);
|
|
|
|
priv->rdp_server = grd_rdp_server_new (priv->context);
|
|
g_signal_connect (priv->rdp_server, "binding-failed",
|
|
G_CALLBACK (on_rdp_server_binding_failed), daemon);
|
|
if (!grd_rdp_server_start (priv->rdp_server, &error))
|
|
{
|
|
g_warning ("Failed to start RDP server: %s\n", error->message);
|
|
stop_rdp_server (daemon);
|
|
}
|
|
else
|
|
{
|
|
g_signal_emit (daemon, signals[RDP_SERVER_STARTED], 0);
|
|
g_message ("RDP server started");
|
|
|
|
if (runtime_mode == GRD_RUNTIME_MODE_HANDOVER ||
|
|
runtime_mode == GRD_RUNTIME_MODE_HEADLESS)
|
|
connect_to_other_rdp_server (daemon);
|
|
}
|
|
}
|
|
|
|
static void
|
|
maybe_start_rdp_server (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdSettings *settings = grd_context_get_settings (priv->context);
|
|
g_autoptr (GError) error = NULL;
|
|
GrdRdpAuthMethods auth_methods = 0;
|
|
g_autofree char *kerberos_keytab = NULL;
|
|
g_autofree char *certificate = NULL;
|
|
g_autofree char *key = NULL;
|
|
gboolean rdp_enabled = FALSE;
|
|
|
|
if (priv->rdp_server)
|
|
return;
|
|
|
|
if (!GRD_DAEMON_GET_CLASS (daemon)->is_daemon_ready (daemon))
|
|
{
|
|
g_debug ("Daemon not ready, not starting RDP server");
|
|
return;
|
|
}
|
|
|
|
g_object_get (G_OBJECT (settings),
|
|
"rdp-enabled", &rdp_enabled,
|
|
"rdp-auth-methods", &auth_methods,
|
|
"rdp-kerberos-keytab", &kerberos_keytab,
|
|
"rdp-server-cert", &certificate,
|
|
"rdp-server-key", &key,
|
|
NULL);
|
|
|
|
if (!rdp_enabled)
|
|
{
|
|
g_debug ("RDP not enabled, not starting RDP server");
|
|
return;
|
|
}
|
|
|
|
if (!auth_methods)
|
|
{
|
|
g_warning ("No RDP auth methods configured, not enabling server.");
|
|
return;
|
|
}
|
|
|
|
if (auth_methods & GRD_RDP_AUTH_METHOD_KERBEROS &&
|
|
!kerberos_keytab)
|
|
{
|
|
g_debug ("Kerberos keytab not set, not starting RDP server");
|
|
return;
|
|
}
|
|
|
|
if ((certificate && key) ||
|
|
grd_context_get_runtime_mode (priv->context) == GRD_RUNTIME_MODE_HANDOVER)
|
|
{
|
|
start_rdp_server (daemon);
|
|
}
|
|
else
|
|
{
|
|
g_message ("RDP TLS certificate and key not yet configured properly");
|
|
start_rdp_server_when_ready (daemon, TRUE);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
restart_rdp_server (gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
priv->restart_rdp_server_source_id = 0;
|
|
|
|
maybe_start_rdp_server (daemon);
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
void
|
|
grd_daemon_restart_rdp_server_with_delay (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
if (priv->restart_rdp_server_source_id)
|
|
return;
|
|
|
|
stop_rdp_server (daemon);
|
|
|
|
priv->restart_rdp_server_source_id =
|
|
g_timeout_add (RDP_SERVER_RESTART_DELAY_MS, restart_rdp_server, daemon);
|
|
}
|
|
#endif /* HAVE_RDP */
|
|
|
|
#ifdef HAVE_VNC
|
|
static gboolean
|
|
set_string_from_auth_method_enum (GBinding *binding,
|
|
const GValue *source_value,
|
|
GValue *target_value,
|
|
gpointer user_data)
|
|
{
|
|
GrdVncAuthMethod src_auth_method = g_value_get_enum (source_value);
|
|
|
|
switch (src_auth_method)
|
|
{
|
|
case GRD_VNC_AUTH_METHOD_PROMPT:
|
|
g_value_set_string (target_value, "prompt");
|
|
break;
|
|
case GRD_VNC_AUTH_METHOD_PASSWORD:
|
|
g_value_set_string (target_value, "password");
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
export_vnc_server_interface (GrdDaemon *daemon)
|
|
{
|
|
GrdDBusRemoteDesktopVncServer *vnc_server_interface;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdSettings *settings = grd_context_get_settings (priv->context);
|
|
|
|
vnc_server_interface =
|
|
grd_dbus_remote_desktop_vnc_server_skeleton_new ();
|
|
|
|
grd_dbus_remote_desktop_vnc_server_set_enabled (vnc_server_interface, FALSE);
|
|
grd_dbus_remote_desktop_vnc_server_set_port (vnc_server_interface, -1);
|
|
g_object_bind_property (settings, "vnc-negotiate-port",
|
|
vnc_server_interface, "negotiate-port",
|
|
G_BINDING_SYNC_CREATE);
|
|
g_object_bind_property (settings, "vnc-view-only",
|
|
vnc_server_interface, "view-only",
|
|
G_BINDING_SYNC_CREATE);
|
|
g_object_bind_property_full (settings, "vnc-auth-method",
|
|
vnc_server_interface, "auth-method",
|
|
G_BINDING_SYNC_CREATE,
|
|
set_string_from_auth_method_enum,
|
|
NULL, NULL, NULL);
|
|
|
|
g_dbus_interface_skeleton_export (
|
|
G_DBUS_INTERFACE_SKELETON (vnc_server_interface),
|
|
priv->connection,
|
|
GRD_VNC_SERVER_OBJECT_PATH,
|
|
NULL);
|
|
|
|
grd_context_set_vnc_server_interface (priv->context, vnc_server_interface);
|
|
}
|
|
|
|
static void
|
|
unexport_vnc_server_interface (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdDBusRemoteDesktopVncServer *vnc_server_interface =
|
|
grd_context_get_vnc_server_interface (priv->context);
|
|
|
|
g_dbus_interface_skeleton_unexport (
|
|
G_DBUS_INTERFACE_SKELETON (vnc_server_interface));
|
|
|
|
grd_context_set_vnc_server_interface (priv->context, NULL);
|
|
}
|
|
|
|
static void
|
|
stop_vnc_server (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
if (!priv->vnc_server)
|
|
return;
|
|
|
|
grd_vnc_server_stop (priv->vnc_server);
|
|
g_clear_object (&priv->vnc_server);
|
|
g_message ("VNC server stopped");
|
|
}
|
|
|
|
static void
|
|
start_vnc_server (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
if (priv->vnc_server)
|
|
return;
|
|
|
|
priv->vnc_server = grd_vnc_server_new (priv->context);
|
|
if (!grd_vnc_server_start (priv->vnc_server, &error))
|
|
{
|
|
g_warning ("Failed to initialize VNC server: %s\n", error->message);
|
|
stop_vnc_server (daemon);
|
|
}
|
|
else
|
|
{
|
|
g_message ("VNC server started");
|
|
}
|
|
}
|
|
#endif /* HAVE_VNC */
|
|
|
|
static void
|
|
export_services_status (GrdDaemon *daemon)
|
|
{
|
|
export_remote_desktop_interface (daemon);
|
|
|
|
#ifdef HAVE_RDP
|
|
export_rdp_server_interface (daemon);
|
|
#endif
|
|
#ifdef HAVE_VNC
|
|
if (GRD_IS_DAEMON_USER (daemon))
|
|
export_vnc_server_interface (daemon);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
unexport_services_status (GrdDaemon *daemon)
|
|
{
|
|
unexport_remote_desktop_interface (daemon);
|
|
|
|
#ifdef HAVE_RDP
|
|
unexport_rdp_server_interface (daemon);
|
|
#endif
|
|
#ifdef HAVE_VNC
|
|
if (GRD_IS_DAEMON_USER (daemon))
|
|
unexport_vnc_server_interface (daemon);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
grd_daemon_maybe_enable_services (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdSettings *settings = grd_context_get_settings (priv->context);
|
|
gboolean rdp_enabled;
|
|
gboolean vnc_enabled;
|
|
|
|
if (!GRD_DAEMON_GET_CLASS (daemon)->is_daemon_ready (daemon))
|
|
return;
|
|
|
|
grd_context_notify_daemon_ready (priv->context);
|
|
|
|
g_object_get (G_OBJECT (settings),
|
|
"rdp-enabled", &rdp_enabled,
|
|
"vnc-enabled", &vnc_enabled,
|
|
NULL);
|
|
|
|
#ifdef HAVE_RDP
|
|
maybe_start_rdp_server (daemon);
|
|
#endif
|
|
|
|
#ifdef HAVE_VNC
|
|
if (vnc_enabled)
|
|
start_vnc_server (daemon);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
grd_daemon_disable_services (GrdDaemon *daemon)
|
|
{
|
|
#ifdef HAVE_RDP
|
|
stop_rdp_server (daemon);
|
|
#endif
|
|
#ifdef HAVE_VNC
|
|
stop_vnc_server (daemon);
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
on_mutter_remote_desktop_proxy_acquired (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdDBusMutterRemoteDesktop *proxy;
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
proxy = grd_dbus_mutter_remote_desktop_proxy_new_finish (result, &error);
|
|
if (!proxy)
|
|
{
|
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
g_warning ("Failed to create remote desktop proxy: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
grd_context_set_mutter_remote_desktop_proxy (priv->context, proxy);
|
|
|
|
g_signal_emit (daemon, signals[MUTTER_PROXY_ACQUIRED], 0);
|
|
}
|
|
|
|
static void
|
|
on_mutter_screen_cast_proxy_acquired (GObject *object,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdDBusMutterScreenCast *proxy;
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
proxy = grd_dbus_mutter_screen_cast_proxy_new_finish (result, &error);
|
|
if (!proxy)
|
|
{
|
|
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
|
g_warning ("Failed to create screen cast proxy: %s", error->message);
|
|
return;
|
|
}
|
|
|
|
grd_context_set_mutter_screen_cast_proxy (priv->context, proxy);
|
|
|
|
g_signal_emit (daemon, signals[MUTTER_PROXY_ACQUIRED], 0);
|
|
}
|
|
|
|
static void
|
|
on_mutter_remote_desktop_name_appeared (GDBusConnection *connection,
|
|
const char *name,
|
|
const char *name_owner,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
grd_dbus_mutter_remote_desktop_proxy_new (connection,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
MUTTER_REMOTE_DESKTOP_BUS_NAME,
|
|
MUTTER_REMOTE_DESKTOP_OBJECT_PATH,
|
|
priv->cancellable,
|
|
on_mutter_remote_desktop_proxy_acquired,
|
|
daemon);
|
|
}
|
|
|
|
static void
|
|
on_mutter_remote_desktop_name_vanished (GDBusConnection *connection,
|
|
const char *name,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
grd_daemon_disable_services (daemon);
|
|
|
|
grd_context_set_mutter_remote_desktop_proxy (priv->context, NULL);
|
|
}
|
|
|
|
static void
|
|
on_mutter_screen_cast_name_appeared (GDBusConnection *connection,
|
|
const char *name,
|
|
const char *name_owner,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
grd_dbus_mutter_screen_cast_proxy_new (connection,
|
|
G_DBUS_PROXY_FLAGS_NONE,
|
|
MUTTER_SCREEN_CAST_BUS_NAME,
|
|
MUTTER_SCREEN_CAST_OBJECT_PATH,
|
|
priv->cancellable,
|
|
on_mutter_screen_cast_proxy_acquired,
|
|
daemon);
|
|
}
|
|
|
|
static void
|
|
on_mutter_screen_cast_name_vanished (GDBusConnection *connection,
|
|
const char *name,
|
|
gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
grd_daemon_disable_services (daemon);
|
|
|
|
grd_context_set_mutter_screen_cast_proxy (priv->context, NULL);
|
|
}
|
|
|
|
void
|
|
grd_daemon_acquire_mutter_dbus_proxies (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
g_clear_handle_id (&priv->mutter_remote_desktop_watch_name_id, g_bus_unwatch_name);
|
|
priv->mutter_remote_desktop_watch_name_id =
|
|
g_bus_watch_name (G_BUS_TYPE_SESSION,
|
|
MUTTER_REMOTE_DESKTOP_BUS_NAME,
|
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
on_mutter_remote_desktop_name_appeared,
|
|
on_mutter_remote_desktop_name_vanished,
|
|
daemon, NULL);
|
|
|
|
g_clear_handle_id (&priv->mutter_screen_cast_watch_name_id, g_bus_unwatch_name);
|
|
priv->mutter_screen_cast_watch_name_id =
|
|
g_bus_watch_name (G_BUS_TYPE_SESSION,
|
|
MUTTER_SCREEN_CAST_BUS_NAME,
|
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
|
on_mutter_screen_cast_name_appeared,
|
|
on_mutter_screen_cast_name_vanished,
|
|
daemon, NULL);
|
|
}
|
|
|
|
#ifdef HAVE_RDP
|
|
static void
|
|
on_rdp_enabled_changed (GrdSettings *settings,
|
|
GParamSpec *pspec,
|
|
GrdDaemon *daemon)
|
|
{
|
|
gboolean rdp_enabled;
|
|
|
|
if (!GRD_DAEMON_GET_CLASS (daemon)->is_daemon_ready (daemon))
|
|
return;
|
|
|
|
g_object_get (G_OBJECT (settings), "rdp-enabled", &rdp_enabled, NULL);
|
|
if (rdp_enabled)
|
|
maybe_start_rdp_server (daemon);
|
|
else
|
|
stop_rdp_server (daemon);
|
|
}
|
|
#endif /* HAVE_RDP */
|
|
|
|
#ifdef HAVE_VNC
|
|
static void
|
|
on_vnc_enabled_changed (GrdSettings *settings,
|
|
GParamSpec *pspec,
|
|
GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
gboolean vnc_enabled;
|
|
|
|
if (!GRD_DAEMON_GET_CLASS (daemon)->is_daemon_ready (daemon))
|
|
return;
|
|
|
|
g_object_get (G_OBJECT (settings), "vnc-enabled", &vnc_enabled, NULL);
|
|
if (vnc_enabled)
|
|
{
|
|
g_return_if_fail (!priv->vnc_server);
|
|
start_vnc_server (daemon);
|
|
}
|
|
else
|
|
{
|
|
stop_vnc_server (daemon);
|
|
}
|
|
}
|
|
#endif /* HAVE_VNC */
|
|
|
|
static void
|
|
grd_daemon_init (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
priv->cancellable = g_cancellable_new ();
|
|
}
|
|
|
|
static GDBusConnection *
|
|
get_daemon_dbus_connection (GrdDaemon *daemon)
|
|
{
|
|
g_autoptr (GDBusConnection) connection = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
|
|
#if defined(HAVE_RDP) && defined(HAVE_LIBSYSTEMD)
|
|
if (GRD_IS_DAEMON_SYSTEM (daemon))
|
|
connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
|
|
else
|
|
#endif /* HAVE_RDP && HAVE_LIBSYSTEMD */
|
|
connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
|
|
|
|
if (!connection)
|
|
{
|
|
g_warning ("Failing acquiring dbus connection: %s", error->message);
|
|
return NULL;
|
|
}
|
|
|
|
return g_steal_pointer (&connection);
|
|
}
|
|
|
|
static void
|
|
grd_daemon_startup (GApplication *app)
|
|
{
|
|
GrdDaemon *daemon = GRD_DAEMON (app);
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
GrdSettings *settings = grd_context_get_settings (priv->context);
|
|
|
|
priv->connection = get_daemon_dbus_connection (daemon);
|
|
export_services_status (daemon);
|
|
|
|
#ifdef HAVE_RDP
|
|
if (GRD_IS_SETTINGS_USER (settings) ||
|
|
GRD_IS_SETTINGS_HEADLESS (settings) ||
|
|
GRD_IS_SETTINGS_SYSTEM (settings))
|
|
{
|
|
g_signal_connect (settings, "notify::rdp-enabled",
|
|
G_CALLBACK (on_rdp_enabled_changed),
|
|
daemon);
|
|
}
|
|
#endif
|
|
#ifdef HAVE_VNC
|
|
if (GRD_IS_SETTINGS_USER (settings) ||
|
|
GRD_IS_SETTINGS_HEADLESS (settings))
|
|
{
|
|
g_signal_connect (settings, "notify::vnc-enabled",
|
|
G_CALLBACK (on_vnc_enabled_changed),
|
|
daemon);
|
|
}
|
|
#endif
|
|
|
|
/* Run indefinitely, until told to exit. */
|
|
g_application_hold (app);
|
|
|
|
G_APPLICATION_CLASS (grd_daemon_parent_class)->startup (app);
|
|
}
|
|
|
|
static void
|
|
grd_daemon_shutdown (GApplication *app)
|
|
{
|
|
GrdDaemon *daemon = GRD_DAEMON (app);
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
g_cancellable_cancel (priv->cancellable);
|
|
g_clear_object (&priv->cancellable);
|
|
|
|
grd_daemon_disable_services (daemon);
|
|
|
|
unexport_services_status (daemon);
|
|
g_clear_object (&priv->connection);
|
|
|
|
grd_context_set_mutter_remote_desktop_proxy (priv->context, NULL);
|
|
g_clear_handle_id (&priv->mutter_remote_desktop_watch_name_id, g_bus_unwatch_name);
|
|
|
|
grd_context_set_mutter_screen_cast_proxy (priv->context, NULL);
|
|
g_clear_handle_id (&priv->mutter_screen_cast_watch_name_id, g_bus_unwatch_name);
|
|
|
|
g_clear_object (&priv->context);
|
|
|
|
if (priv->sigterm_source)
|
|
{
|
|
g_source_destroy (priv->sigterm_source);
|
|
g_clear_pointer (&priv->sigterm_source, g_source_unref);
|
|
}
|
|
if (priv->sigint_source)
|
|
{
|
|
g_source_destroy (priv->sigint_source);
|
|
g_clear_pointer (&priv->sigint_source, g_source_unref);
|
|
}
|
|
|
|
G_APPLICATION_CLASS (grd_daemon_parent_class)->shutdown (app);
|
|
}
|
|
|
|
static void
|
|
grd_daemon_get_property (GObject *object,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GrdDaemon *daemon = GRD_DAEMON (object);
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_CONTEXT:
|
|
g_value_set_object (value, priv->context);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
grd_daemon_set_property (GObject *object,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GrdDaemon *daemon = GRD_DAEMON (object);
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_CONTEXT:
|
|
priv->context = g_value_get_object (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
grd_daemon_class_init (GrdDaemonClass *klass)
|
|
{
|
|
GApplicationClass *g_application_class = G_APPLICATION_CLASS (klass);
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
g_application_class->startup = grd_daemon_startup;
|
|
g_application_class->shutdown = grd_daemon_shutdown;
|
|
|
|
object_class->get_property = grd_daemon_get_property;
|
|
object_class->set_property = grd_daemon_set_property;
|
|
|
|
g_object_class_install_property (object_class,
|
|
PROP_CONTEXT,
|
|
g_param_spec_object ("context",
|
|
"GrdContext",
|
|
"The GrdContext instance",
|
|
GRD_TYPE_CONTEXT,
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_STATIC_STRINGS));
|
|
|
|
signals[MUTTER_PROXY_ACQUIRED] = g_signal_new ("mutter-proxy-acquired",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
0,
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 0);
|
|
signals[RDP_SERVER_STARTED] = g_signal_new ("rdp-server-started",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
0,
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 0);
|
|
signals[RDP_SERVER_STOPPED] = g_signal_new ("rdp-server-stopped",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
0,
|
|
NULL, NULL, NULL,
|
|
G_TYPE_NONE, 0);
|
|
|
|
grd_dbus_error_quark ();
|
|
}
|
|
|
|
static void
|
|
activate_terminate (GAction *action,
|
|
GVariant *parameter,
|
|
GrdDaemon *daemon)
|
|
{
|
|
g_application_release (G_APPLICATION (daemon));
|
|
}
|
|
|
|
static void
|
|
add_actions (GApplication *app)
|
|
{
|
|
g_autoptr(GSimpleAction) action = NULL;
|
|
|
|
action = g_simple_action_new ("terminate", NULL);
|
|
g_signal_connect (action, "activate", G_CALLBACK (activate_terminate), app);
|
|
g_action_map_add_action (G_ACTION_MAP (app), G_ACTION (action));
|
|
}
|
|
|
|
static gboolean
|
|
sigint_terminate_daemon (gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
g_debug ("Received SIGINT signal. Exiting...");
|
|
g_clear_pointer (&priv->sigint_source, g_source_unref);
|
|
g_application_release (G_APPLICATION (daemon));
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static gboolean
|
|
sigterm_terminate_daemon (gpointer user_data)
|
|
{
|
|
GrdDaemon *daemon = user_data;
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
g_debug ("Received SIGTERM signal. Exiting...");
|
|
g_clear_pointer (&priv->sigterm_source, g_source_unref);
|
|
g_application_release (G_APPLICATION (daemon));
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
static void
|
|
register_signals (GrdDaemon *daemon)
|
|
{
|
|
GrdDaemonPrivate *priv = grd_daemon_get_instance_private (daemon);
|
|
|
|
priv->sigint_source = g_unix_signal_source_new (SIGINT);
|
|
g_source_set_callback (priv->sigint_source, sigint_terminate_daemon,
|
|
daemon, NULL);
|
|
g_source_attach (priv->sigint_source, NULL);
|
|
|
|
priv->sigterm_source = g_unix_signal_source_new (SIGTERM);
|
|
g_source_set_callback (priv->sigterm_source, sigterm_terminate_daemon,
|
|
daemon, NULL);
|
|
g_source_attach (priv->sigterm_source, NULL);
|
|
}
|
|
|
|
static int
|
|
count_trues (int n_args, ...)
|
|
{
|
|
va_list booleans;
|
|
int booleans_count = 0;
|
|
|
|
va_start (booleans, n_args);
|
|
|
|
for (int i = 0; i < n_args; ++i)
|
|
booleans_count += va_arg (booleans, gboolean) ? 1 : 0;
|
|
|
|
return booleans_count;
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
GrdContext *context;
|
|
GrdSettings *settings;
|
|
gboolean print_version = FALSE;
|
|
gboolean headless = FALSE;
|
|
gboolean system = FALSE;
|
|
gboolean handover = FALSE;
|
|
int rdp_port = -1;
|
|
int vnc_port = -1;
|
|
int max_parallel_connections = DEFAULT_MAX_PARALLEL_CONNECTIONS;
|
|
|
|
GOptionEntry entries[] = {
|
|
{ "version", 0, 0, G_OPTION_ARG_NONE, &print_version,
|
|
"Print version", NULL },
|
|
{ "headless", 0, 0, G_OPTION_ARG_NONE, &headless,
|
|
"Run in headless mode", NULL },
|
|
#if defined(HAVE_RDP) && defined(HAVE_LIBSYSTEMD)
|
|
{ "system", 0, 0, G_OPTION_ARG_NONE, &system,
|
|
"Run in headless mode as a system g-r-d service", NULL },
|
|
{ "handover", 0, 0, G_OPTION_ARG_NONE, &handover,
|
|
"Run in headless mode taking a connection from system g-r-d service", NULL },
|
|
#endif /* HAVE_RDP && HAVE_LIBSYSTEMD */
|
|
{ "rdp-port", 0, 0, G_OPTION_ARG_INT, &rdp_port,
|
|
"RDP port", NULL },
|
|
{ "vnc-port", 0, 0, G_OPTION_ARG_INT, &vnc_port,
|
|
"VNC port", NULL },
|
|
{ "max-parallel-connections", 0, 0,
|
|
G_OPTION_ARG_INT, &max_parallel_connections,
|
|
"Max number of parallel connections (0 for unlimited, "
|
|
"default: " QUOTE(DEFAULT_MAX_PARALLEL_CONNECTIONS) ")", NULL },
|
|
{ NULL }
|
|
};
|
|
g_autoptr (GOptionContext) option_context = NULL;
|
|
g_autoptr (GrdDaemon) daemon = NULL;
|
|
g_autoptr (GError) error = NULL;
|
|
GrdRuntimeMode runtime_mode;
|
|
|
|
g_set_application_name (_("GNOME Remote Desktop"));
|
|
|
|
option_context = g_option_context_new (NULL);
|
|
g_option_context_add_main_entries (option_context, entries, GETTEXT_PACKAGE);
|
|
if (!g_option_context_parse (option_context, &argc, &argv, &error))
|
|
{
|
|
g_printerr ("Invalid option: %s\n", error->message);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (print_version)
|
|
{
|
|
g_print ("GNOME Remote Desktop %s\n", VERSION);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
if (count_trues (3, headless, system, handover) > 1)
|
|
{
|
|
g_printerr ("Invalid option: More than one runtime mode specified\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (max_parallel_connections == 0)
|
|
{
|
|
max_parallel_connections = INT_MAX;
|
|
}
|
|
else if (max_parallel_connections < 0)
|
|
{
|
|
g_printerr ("Invalid number of max parallel connections: %d\n",
|
|
max_parallel_connections);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (headless)
|
|
runtime_mode = GRD_RUNTIME_MODE_HEADLESS;
|
|
else if (system)
|
|
runtime_mode = GRD_RUNTIME_MODE_SYSTEM;
|
|
else if (handover)
|
|
runtime_mode = GRD_RUNTIME_MODE_HANDOVER;
|
|
else
|
|
runtime_mode = GRD_RUNTIME_MODE_SCREEN_SHARE;
|
|
|
|
switch (runtime_mode)
|
|
{
|
|
case GRD_RUNTIME_MODE_SCREEN_SHARE:
|
|
case GRD_RUNTIME_MODE_HEADLESS:
|
|
daemon = GRD_DAEMON (grd_daemon_user_new (runtime_mode, &error));
|
|
break;
|
|
#ifdef HAVE_LIBSYSTEMD
|
|
case GRD_RUNTIME_MODE_SYSTEM:
|
|
daemon = GRD_DAEMON (grd_daemon_system_new (&error));
|
|
break;
|
|
case GRD_RUNTIME_MODE_HANDOVER:
|
|
daemon = GRD_DAEMON (grd_daemon_handover_new (&error));
|
|
break;
|
|
#else
|
|
case GRD_RUNTIME_MODE_SYSTEM:
|
|
case GRD_RUNTIME_MODE_HANDOVER:
|
|
g_assert_not_reached ();
|
|
break;
|
|
#endif /* HAVE_LIBSYSTEMD */
|
|
}
|
|
|
|
if (!daemon)
|
|
{
|
|
g_printerr ("Failed to initialize: %s\n", error->message);
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
add_actions (G_APPLICATION (daemon));
|
|
register_signals (daemon);
|
|
|
|
context = grd_daemon_get_context (daemon);
|
|
settings = grd_context_get_settings (context);
|
|
if (rdp_port != -1)
|
|
grd_settings_override_rdp_port (settings, rdp_port);
|
|
if (vnc_port != -1)
|
|
grd_settings_override_vnc_port (settings, vnc_port);
|
|
|
|
grd_settings_override_max_parallel_connections (settings,
|
|
max_parallel_connections);
|
|
|
|
return g_application_run (G_APPLICATION (daemon), argc, argv);
|
|
}
|