[gtk-vnc] src: add support for VNC power control actions
- From: Daniel P. Berrange <dberrange src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk-vnc] src: add support for VNC power control actions
- Date: Fri, 11 Dec 2020 18:26:12 +0000 (UTC)
commit e9526038756bfd2e0cce07a8412282613f51d0a7
Author: Daniel P. Berrangé <dan berrange com>
Date: Fri Dec 11 11:42:00 2020 +0000
src: add support for VNC power control actions
This allows a client to request shutdown/reboot/reset of remote virtual
machines when appropriate.
Signed-off-by: Daniel P. Berrangé <berrange redhat com>
src/libgvnc_sym.version | 3 ++
src/vncconnection.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++--
src/vncconnection.h | 15 +++++-
src/vncdisplay.c | 45 +++++++++++++++++
4 files changed, 190 insertions(+), 5 deletions(-)
---
diff --git a/src/libgvnc_sym.version b/src/libgvnc_sym.version
index d029a81..85b90ee 100644
--- a/src/libgvnc_sym.version
+++ b/src/libgvnc_sym.version
@@ -82,12 +82,15 @@
vnc_connection_auth_get_type;
vnc_connection_auth_vencrypt_get_type;
vnc_connection_credential_get_type;
+ vnc_connection_power_action_get_type;
vnc_connection_audio_enable;
vnc_connection_audio_disable;
vnc_connection_set_audio_format;
vnc_connection_get_audio_format;
vnc_connection_set_audio;
vnc_connection_get_ledstate;
+ vnc_connection_get_power_control;
+ vnc_connection_power_control;
vnc_util_set_debug;
vnc_util_get_debug;
diff --git a/src/vncconnection.c b/src/vncconnection.c
index 13900b0..d335700 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -77,6 +77,7 @@ typedef enum {
VNC_CONNECTION_SERVER_MESSAGE_SET_COLOR_MAP_ENTRIES = 1,
VNC_CONNECTION_SERVER_MESSAGE_BELL = 2,
VNC_CONNECTION_SERVER_MESSAGE_SERVER_CUT_TEXT = 3,
+ VNC_CONNECTION_SERVER_MESSAGE_XVP = 250,
VNC_CONNECTION_SERVER_MESSAGE_QEMU = 255,
} VncConnectionServerMessage;
@@ -98,6 +99,7 @@ typedef enum {
VNC_CONNECTION_CLIENT_MESSAGE_KEY = 4,
VNC_CONNECTION_CLIENT_MESSAGE_POINTER = 5,
VNC_CONNECTION_CLIENT_MESSAGE_CUT_TEXT = 6,
+ VNC_CONNECTION_CLIENT_MESSAGE_XVP = 250,
VNC_CONNECTION_CLIENT_MESSAGE_QEMU = 255,
} VncConnectionClientMessage;
@@ -112,6 +114,10 @@ typedef enum {
VNC_CONNECTION_CLIENT_MESSAGE_QEMU_AUDIO_SET_FORMAT = 2,
} VncConnectionClientMessageQEMUAudio;
+typedef enum {
+ VNC_CONNECTION_XVP_FAIL = 0,
+ VNC_CONNECTION_XVP_INIT = 1,
+} VncConnectionXVPCode;
typedef void vnc_connection_rich_cursor_blt_func(VncConnection *conn, guint8 *, guint8 *,
guint8 *, int, guint16, guint16);
@@ -201,6 +207,7 @@ struct _VncConnectionPrivate
VncCursor *cursor;
gboolean absPointer;
gboolean sharedFlag;
+ gboolean powerControl;
vnc_connection_rich_cursor_blt_func *rich_cursor_blt;
vnc_connection_tight_compute_predicted_func *tight_compute_predicted;
@@ -259,6 +266,8 @@ enum {
VNC_DESKTOP_RESIZE,
VNC_PIXEL_FORMAT_CHANGED,
VNC_LED_STATE,
+ VNC_POWER_CONTROL_INITIALIZED,
+ VNC_POWER_CONTROL_FAILED,
VNC_AUTH_FAILURE,
VNC_AUTH_UNSUPPORTED,
@@ -274,10 +283,7 @@ enum {
VNC_LAST_SIGNAL,
};
-static guint signals[VNC_LAST_SIGNAL] = { 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0 };
+static guint signals[VNC_LAST_SIGNAL] = { 0 };
#define nibhi(a) (((a) >> 4) & 0x0F)
#define niblo(a) ((a) & 0x0F)
@@ -491,6 +497,7 @@ struct signal_data
GValueArray *authCred;
GValueArray *authTypes;
const char *message;
+ int powerStatus;
} params;
};
@@ -559,6 +566,18 @@ static gboolean do_vnc_connection_emit_main_context(gpointer opaque)
data->params.ledstate);
break;
+ case VNC_POWER_CONTROL_INITIALIZED:
+ g_signal_emit(G_OBJECT(data->conn),
+ signals[data->signum],
+ 0);
+ break;
+
+ case VNC_POWER_CONTROL_FAILED:
+ g_signal_emit(G_OBJECT(data->conn),
+ signals[data->signum],
+ 0);
+ break;
+
case VNC_AUTH_FAILURE:
g_signal_emit(G_OBJECT(data->conn),
signals[data->signum],
@@ -3538,6 +3557,35 @@ static gboolean vnc_connection_server_message(VncConnection *conn)
vnc_connection_server_cut_text(conn, data, n_text);
g_free(data);
} break;
+ case VNC_CONNECTION_SERVER_MESSAGE_XVP: {
+ guint8 pad[1];
+ guint8 version;
+ guint8 code;
+ struct signal_data s;
+ vnc_connection_read(conn, pad, 1);
+ version = vnc_connection_read_u8(conn);
+ code = vnc_connection_read_u8(conn);
+
+ if (version < 1) {
+ vnc_connection_set_error(conn, "Invalid XVP version %d", version);
+ break;
+ }
+
+ switch (code) {
+ case VNC_CONNECTION_XVP_FAIL:
+ VNC_DEBUG("XVP power control action failed");
+ vnc_connection_emit_main_context(conn, VNC_POWER_CONTROL_FAILED, &s);
+ break;
+ case VNC_CONNECTION_XVP_INIT:
+ VNC_DEBUG("XVP power control available");
+ priv->powerControl = TRUE;
+ vnc_connection_emit_main_context(conn, VNC_POWER_CONTROL_INITIALIZED, &s);
+ break;
+ default:
+ vnc_connection_set_error(conn, "Invalid XVP code %d", code);
+ break;
+ }
+ } break;
case VNC_CONNECTION_SERVER_MESSAGE_QEMU: {
guint8 n_type;
@@ -5166,6 +5214,26 @@ static void vnc_connection_class_init(VncConnectionClass *klass)
G_TYPE_NONE,
0);
+ signals[VNC_POWER_CONTROL_INITIALIZED] =
+ g_signal_new ("vnc-power-control-initialized",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (VncConnectionClass, vnc_power_control_initialized),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals[VNC_POWER_CONTROL_FAILED] =
+ g_signal_new ("vnc-power-control-failed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (VncConnectionClass, vnc_power_control_failed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
signals[VNC_AUTH_FAILURE] =
g_signal_new ("vnc-auth-failure",
G_OBJECT_CLASS_TYPE (object_class),
@@ -6336,6 +6404,62 @@ int vnc_connection_get_ledstate(VncConnection *conn)
return priv->ledstate;
}
+/**
+ * vnc_connection_get_power_control:
+ * @conn: (transfer none): the connection object
+ *
+ * Determine if the remote server supports power control.
+ * This will only be valid once the "vnc-initialized"
+ * signal has been emitted.
+ *
+ * Returns: TRUE if the server supports power control
+ */
+gboolean vnc_connection_get_power_control(VncConnection *conn)
+{
+ VncConnectionPrivate *priv = conn->priv;
+
+ return priv->powerControl;
+}
+
+
+/**
+ * vnc_connection_power_control:
+ * @conn: (transfer none): the connection object
+ *
+ * Perform a power control action on the remote server.
+ *
+ * This is only valid if the "vnc-power-control" signal
+ * has been emitted with a VNC_CONNECTION_POWER_STATUS_INIT
+ * code.
+ *
+ * The action should be assumed to be accepted unless
+ * "vnc-power-control" signal is emitted with a
+ * VNC_CONNECTION_POWER_STATUS_FAIL code.
+ *
+ * Returns: TRUE if the action was sent, FALSE if
+ * power control is not supported
+ */
+gboolean vnc_connection_power_control(VncConnection *conn,
+ VncConnectionPowerAction action)
+{
+ VncConnectionPrivate *priv = conn->priv;
+
+ if (!priv->powerControl)
+ return FALSE;
+
+ VNC_DEBUG("Sendng power control action %d", action);
+
+ vnc_connection_buffered_write_u8(conn, VNC_CONNECTION_CLIENT_MESSAGE_XVP);
+ vnc_connection_buffered_write_u8(conn, 0); /* pad */
+ vnc_connection_buffered_write_u8(conn, 1); /* version */
+ vnc_connection_buffered_write_u8(conn, action);
+ vnc_connection_buffered_flush(conn);
+
+ return !vnc_connection_has_error(conn);
+}
+
+
+
/*
* Local variables:
* c-indent-level: 4
diff --git a/src/vncconnection.h b/src/vncconnection.h
index f203caf..aac2a6b 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -80,12 +80,14 @@ struct _VncConnectionClass
void (*vnc_disconnected)(VncConnection *conn);
void (*vnc_led_state)(VncConnection *conn);
void (*vnc_error)(VncConnection *conn, const char *message);
+ void (*vnc_power_control_initialized)(VncConnection *conn);
+ void (*vnc_power_control_failed)(VncConnection *conn);
/*
* If adding fields to this struct, remove corresponding
* amount of padding to avoid changing overall struct size
*/
- gpointer _vnc_reserved[VNC_PADDING_LARGE - 2];
+ gpointer _vnc_reserved[VNC_PADDING_LARGE - 4];
};
@@ -123,6 +125,7 @@ typedef enum {
VNC_CONNECTION_ENCODING_AUDIO = -259,
VNC_CONNECTION_ENCODING_LED_STATE = -261,
+ VNC_CONNECTION_ENCODING_XVP = -309,
VNC_CONNECTION_ENCODING_ALPHA_CURSOR = -314,
} VncConnectionEncoding;
@@ -160,6 +163,12 @@ typedef enum {
VNC_CONNECTION_CREDENTIAL_CLIENTNAME,
} VncConnectionCredential;
+typedef enum {
+ VNC_CONNECTION_POWER_ACTION_SHUTDOWN = 2,
+ VNC_CONNECTION_POWER_ACTION_REBOOT = 3,
+ VNC_CONNECTION_POWER_ACTION_RESET = 4,
+} VncConnectionPowerAction;
+
GType vnc_connection_get_type(void) G_GNUC_CONST;
VncConnection *vnc_connection_new(void);
@@ -214,6 +223,7 @@ VncCursor *vnc_connection_get_cursor(VncConnection *conn);
gboolean vnc_connection_get_abs_pointer(VncConnection *conn);
gboolean vnc_connection_get_ext_key_event(VncConnection *conn);
+gboolean vnc_connection_get_power_control(VncConnection *conn);
int vnc_connection_get_ledstate(VncConnection *conn);
gboolean vnc_connection_set_audio(VncConnection *conn,
@@ -226,6 +236,9 @@ const VncAudioFormat *vnc_connection_get_audio_format(VncConnection *conn);
gboolean vnc_connection_audio_enable(VncConnection *conn);
gboolean vnc_connection_audio_disable(VncConnection *conn);
+gboolean vnc_connection_power_control(VncConnection *conn,
+ VncConnectionPowerAction action);
+
G_END_DECLS
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 1d14932..ae9a1bd 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -139,6 +139,8 @@ typedef enum
VNC_SERVER_CUT_TEXT,
VNC_BELL,
VNC_ERROR,
+ VNC_POWER_CONTROL_INITIALIZED,
+ VNC_POWER_CONTROL_FAILED,
LAST_SIGNAL
} vnc_display_signals;
@@ -1601,6 +1603,21 @@ static void on_error(VncConnection *conn G_GNUC_UNUSED,
VNC_DEBUG("VNC server error");
}
+static void on_power_control_init(VncConnection *conn G_GNUC_UNUSED,
+ gpointer opaque)
+{
+ VncDisplay *obj = VNC_DISPLAY(opaque);
+
+ g_signal_emit(G_OBJECT(obj), signals[VNC_POWER_CONTROL_INITIALIZED], 0);
+}
+
+static void on_power_control_fail(VncConnection *conn G_GNUC_UNUSED,
+ gpointer opaque)
+{
+ VncDisplay *obj = VNC_DISPLAY(opaque);
+
+ g_signal_emit(G_OBJECT(obj), signals[VNC_POWER_CONTROL_FAILED], 0);
+}
static void on_initialized(VncConnection *conn G_GNUC_UNUSED,
gpointer opaque)
@@ -1613,6 +1630,7 @@ static void on_initialized(VncConnection *conn G_GNUC_UNUSED,
* server prefers when it has a choice to use */
gint32 encodings[] = { VNC_CONNECTION_ENCODING_TIGHT_JPEG5,
VNC_CONNECTION_ENCODING_TIGHT,
+ VNC_CONNECTION_ENCODING_XVP,
VNC_CONNECTION_ENCODING_EXT_KEY_EVENT,
VNC_CONNECTION_ENCODING_LED_STATE,
VNC_CONNECTION_ENCODING_DESKTOP_RESIZE,
@@ -2421,6 +2439,29 @@ static void vnc_display_class_init(VncDisplayClass *klass)
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE,
0);
+
+ signals[VNC_POWER_CONTROL_INITIALIZED] =
+ g_signal_new("vnc-power-control-initialized",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals[VNC_POWER_CONTROL_FAILED] =
+ g_signal_new("vnc-power-control-failed",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_HOOKS,
+ 0,
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
}
static void vnc_display_init(VncDisplay *display)
@@ -2546,6 +2587,10 @@ static void vnc_display_init(VncDisplay *display)
G_CALLBACK(on_disconnected), display);
g_signal_connect(G_OBJECT(priv->conn), "vnc-error",
G_CALLBACK(on_error), display);
+ g_signal_connect(G_OBJECT(priv->conn), "vnc-power-control-initialized",
+ G_CALLBACK(on_power_control_init), display);
+ g_signal_connect(G_OBJECT(priv->conn), "vnc-power-control-failed",
+ G_CALLBACK(on_power_control_fail), display);
priv->keycode_map = vnc_display_keymap_gdk2rfb_table(&priv->keycode_maplen);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]