summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qemu-options.hx4
-rw-r--r--ui/vnc.c59
-rw-r--r--ui/vnc.h13
3 files changed, 76 insertions, 0 deletions
diff --git a/qemu-options.hx b/qemu-options.hx
index 1698a0c751..05fe35ceb6 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2222,6 +2222,10 @@ SRST
transmission. When not using an -audiodev argument, this option
must be omitted, otherwise is must be present and specify a
valid audiodev.
+
+ ``power-control``
+ Permit the remote client to issue shutdown, reboot or reset power
+ control requests.
ERST
ARCHHEADING(, QEMU_ARCH_I386)
diff --git a/ui/vnc.c b/ui/vnc.c
index 69e92b1ef3..a0bf750767 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -30,6 +30,7 @@
#include "trace.h"
#include "hw/qdev-core.h"
#include "sysemu/sysemu.h"
+#include "sysemu/runstate.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "qemu/module.h"
@@ -2042,6 +2043,17 @@ static void send_ext_audio_ack(VncState *vs)
vnc_flush(vs);
}
+static void send_xvp_message(VncState *vs, int code)
+{
+ vnc_lock_output(vs);
+ vnc_write_u8(vs, VNC_MSG_SERVER_XVP);
+ vnc_write_u8(vs, 0); /* pad */
+ vnc_write_u8(vs, 1); /* version */
+ vnc_write_u8(vs, code);
+ vnc_unlock_output(vs);
+ vnc_flush(vs);
+}
+
static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
{
int i;
@@ -2121,6 +2133,12 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
case VNC_ENCODING_LED_STATE:
vs->features |= VNC_FEATURE_LED_STATE_MASK;
break;
+ case VNC_ENCODING_XVP:
+ if (vs->vd->power_control) {
+ vs->features |= VNC_FEATURE_XVP;
+ send_xvp_message(vs, VNC_XVP_CODE_INIT);
+ }
+ break;
case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9:
vs->tight->compression = (enc & 0x0F);
break;
@@ -2353,6 +2371,42 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
client_cut_text(vs, read_u32(data, 4), data + 8);
break;
+ case VNC_MSG_CLIENT_XVP:
+ if (!(vs->features & VNC_FEATURE_XVP)) {
+ error_report("vnc: xvp client message while disabled");
+ vnc_client_error(vs);
+ break;
+ }
+ if (len == 1) {
+ return 4;
+ }
+ if (len == 4) {
+ uint8_t version = read_u8(data, 2);
+ uint8_t action = read_u8(data, 3);
+
+ if (version != 1) {
+ error_report("vnc: xvp client message version %d != 1",
+ version);
+ vnc_client_error(vs);
+ break;
+ }
+
+ switch (action) {
+ case VNC_XVP_ACTION_SHUTDOWN:
+ qemu_system_powerdown_request();
+ break;
+ case VNC_XVP_ACTION_REBOOT:
+ send_xvp_message(vs, VNC_XVP_CODE_FAIL);
+ break;
+ case VNC_XVP_ACTION_RESET:
+ qemu_system_reset_request(SHUTDOWN_CAUSE_HOST_QMP_SYSTEM_RESET);
+ break;
+ default:
+ send_xvp_message(vs, VNC_XVP_CODE_FAIL);
+ break;
+ }
+ }
+ break;
case VNC_MSG_CLIENT_QEMU:
if (len == 1)
return 2;
@@ -3379,6 +3433,9 @@ static QemuOptsList qemu_vnc_opts = {
},{
.name = "audiodev",
.type = QEMU_OPT_STRING,
+ },{
+ .name = "power-control",
+ .type = QEMU_OPT_BOOL,
},
{ /* end of list */ }
},
@@ -3942,6 +3999,8 @@ void vnc_display_open(const char *id, Error **errp)
vd->non_adaptive = true;
}
+ vd->power_control = qemu_opt_get_bool(opts, "power-control", false);
+
if (tlsauthz) {
vd->tlsauthzid = g_strdup(tlsauthz);
} else if (acl) {
diff --git a/ui/vnc.h b/ui/vnc.h
index c8d3ad9ec4..5feeef9df0 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -176,6 +176,7 @@ struct VncDisplay
int ws_subauth; /* Used by websockets */
bool lossy;
bool non_adaptive;
+ bool power_control;
QCryptoTLSCreds *tlscreds;
QAuthZ *tlsauthz;
char *tlsauthzid;
@@ -412,6 +413,7 @@ enum {
#define VNC_ENCODING_TIGHT_PNG 0xFFFFFEFC /* -260 */
#define VNC_ENCODING_LED_STATE 0XFFFFFEFB /* -261 */
#define VNC_ENCODING_DESKTOP_RESIZE_EXT 0XFFFFFECC /* -308 */
+#define VNC_ENCODING_XVP 0XFFFFFECB /* -309 */
#define VNC_ENCODING_ALPHA_CURSOR 0XFFFFFEC6 /* -314 */
#define VNC_ENCODING_WMVi 0x574D5669
@@ -453,6 +455,7 @@ enum VncFeatures {
VNC_FEATURE_ZRLE,
VNC_FEATURE_ZYWRLE,
VNC_FEATURE_LED_STATE,
+ VNC_FEATURE_XVP,
};
#define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
@@ -467,6 +470,7 @@ enum VncFeatures {
#define VNC_FEATURE_ZRLE_MASK (1 << VNC_FEATURE_ZRLE)
#define VNC_FEATURE_ZYWRLE_MASK (1 << VNC_FEATURE_ZYWRLE)
#define VNC_FEATURE_LED_STATE_MASK (1 << VNC_FEATURE_LED_STATE)
+#define VNC_FEATURE_XVP_MASK (1 << VNC_FEATURE_XVP)
/* Client -> Server message IDs */
@@ -519,6 +523,15 @@ enum VncFeatures {
#define VNC_MSG_SERVER_QEMU_AUDIO_BEGIN 1
#define VNC_MSG_SERVER_QEMU_AUDIO_DATA 2
+/* XVP server -> client status code */
+#define VNC_XVP_CODE_FAIL 0
+#define VNC_XVP_CODE_INIT 1
+
+/* XVP client -> server action request */
+#define VNC_XVP_ACTION_SHUTDOWN 2
+#define VNC_XVP_ACTION_REBOOT 3
+#define VNC_XVP_ACTION_RESET 4
+
/*****************************************************************************
*