mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/kraxel/tags/pull-vnc-20150122-1' into staging
vnc: add support for multiple vnc displays # gpg: Signature made Thu 22 Jan 2015 11:00:54 GMT using RSA key ID D3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" * remotes/kraxel/tags/pull-vnc-20150122-1: monitor: add vnc websockets monitor: add query-vnc-servers command vnc: factor out qmp_query_client_list vnc: track & limit connections vnc: update docs/multiseat.txt vnc: allow binding servers to qemu consoles vnc: switch to QemuOpts, allow multiple servers vnc: add display id to acl names vnc: remove unused DisplayState parameter, add id instead. vnc: remove vnc_display global Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+14
-4
@@ -7,7 +7,7 @@ host side
|
||||
|
||||
First you must compile qemu with a user interface supporting
|
||||
multihead/multiseat and input event routing. Right now this
|
||||
list includes sdl2 and gtk (both 2+3):
|
||||
list includes sdl2, gtk (both 2+3) and vnc:
|
||||
|
||||
./configure --enable-sdl --with-sdlabi=2.0
|
||||
|
||||
@@ -16,16 +16,16 @@ or
|
||||
./configure --enable-gtk
|
||||
|
||||
|
||||
Next put together the qemu command line:
|
||||
Next put together the qemu command line (sdk/gtk):
|
||||
|
||||
qemu -enable-kvm -usb $memory $disk $whatever \
|
||||
-display [ sdl | gtk ] \
|
||||
-vga std \
|
||||
-device usb-tablet
|
||||
|
||||
That is it for the first head, which will use the standard vga, the
|
||||
That is it for the first seat, which will use the standard vga, the
|
||||
standard ps/2 keyboard (implicitly there) and the usb-tablet. Now the
|
||||
additional switches for the second head:
|
||||
additional switches for the second seat:
|
||||
|
||||
-device pci-bridge,addr=12.0,chassis_nr=2,id=head.2 \
|
||||
-device secondary-vga,bus=head.2,addr=02.0,id=video.2 \
|
||||
@@ -47,6 +47,16 @@ in a separate tab. You can either simply switch tabs to switch heads,
|
||||
or use the "View / Detach tab" menu item to move one of the displays
|
||||
to its own window so you can see both display devices side-by-side.
|
||||
|
||||
For vnc some additional configuration on the command line is needed.
|
||||
We'll create two vnc server instances, and bind the second one to the
|
||||
second seat, simliar to input devices:
|
||||
|
||||
-display vnc=:1,id=primary \
|
||||
-display vnc=:2,id=secondary,display=video.2
|
||||
|
||||
Connecting to vnc display :1 gives you access to the first seat, and
|
||||
likewise connecting to vnc display :2 shows the second seat.
|
||||
|
||||
Note on spice: Spice handles multihead just fine. But it can't do
|
||||
multiseat. For tablet events the event source is sent to the spice
|
||||
agent. But qemu can't figure it, so it can't do input routing.
|
||||
|
||||
+10
-8
@@ -331,19 +331,21 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
|
||||
void cocoa_display_init(DisplayState *ds, int full_screen);
|
||||
|
||||
/* vnc.c */
|
||||
void vnc_display_init(DisplayState *ds);
|
||||
void vnc_display_open(DisplayState *ds, const char *display, Error **errp);
|
||||
void vnc_display_add_client(DisplayState *ds, int csock, bool skipauth);
|
||||
char *vnc_display_local_addr(DisplayState *ds);
|
||||
void vnc_display_init(const char *id);
|
||||
void vnc_display_open(const char *id, Error **errp);
|
||||
void vnc_display_add_client(const char *id, int csock, bool skipauth);
|
||||
char *vnc_display_local_addr(const char *id);
|
||||
#ifdef CONFIG_VNC
|
||||
int vnc_display_password(DisplayState *ds, const char *password);
|
||||
int vnc_display_pw_expire(DisplayState *ds, time_t expires);
|
||||
int vnc_display_password(const char *id, const char *password);
|
||||
int vnc_display_pw_expire(const char *id, time_t expires);
|
||||
QemuOpts *vnc_parse_func(const char *str);
|
||||
int vnc_init_func(QemuOpts *opts, void *opaque);
|
||||
#else
|
||||
static inline int vnc_display_password(DisplayState *ds, const char *password)
|
||||
static inline int vnc_display_password(const char *id, const char *password)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires)
|
||||
static inline int vnc_display_pw_expire(const char *id, time_t expires)
|
||||
{
|
||||
return -ENODEV;
|
||||
};
|
||||
|
||||
+72
-1
@@ -672,12 +672,15 @@
|
||||
#
|
||||
# @family: address family
|
||||
#
|
||||
# @websocket: true in case the socket is a websocket (since 2.3).
|
||||
#
|
||||
# Since: 2.1
|
||||
##
|
||||
{ 'type': 'VncBasicInfo',
|
||||
'data': { 'host': 'str',
|
||||
'service': 'str',
|
||||
'family': 'NetworkAddressFamily' } }
|
||||
'family': 'NetworkAddressFamily',
|
||||
'websocket': 'bool' } }
|
||||
|
||||
##
|
||||
# @VncServerInfo
|
||||
@@ -750,6 +753,63 @@
|
||||
'*family': 'NetworkAddressFamily',
|
||||
'*service': 'str', '*auth': 'str', '*clients': ['VncClientInfo']} }
|
||||
|
||||
##
|
||||
# @VncPriAuth:
|
||||
#
|
||||
# vnc primary authentication method.
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
{ 'enum': 'VncPrimaryAuth',
|
||||
'data': [ 'none', 'vnc', 'ra2', 'ra2ne', 'tight', 'ultra',
|
||||
'tls', 'vencrypt', 'sasl' ] }
|
||||
|
||||
##
|
||||
# @VncVencryptSubAuth:
|
||||
#
|
||||
# vnc sub authentication method with vencrypt.
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
{ 'enum': 'VncVencryptSubAuth',
|
||||
'data': [ 'plain',
|
||||
'tls-none', 'x509-none',
|
||||
'tls-vnc', 'x509-vnc',
|
||||
'tls-plain', 'x509-plain',
|
||||
'tls-sasl', 'x509-sasl' ] }
|
||||
|
||||
##
|
||||
# @VncInfo2:
|
||||
#
|
||||
# Information about a vnc server
|
||||
#
|
||||
# @id: vnc server name.
|
||||
#
|
||||
# @server: A list of @VncBasincInfo describing all listening sockets.
|
||||
# The list can be empty (in case the vnc server is disabled).
|
||||
# It also may have multiple entries: normal + websocket,
|
||||
# possibly also ipv4 + ipv6 in the future.
|
||||
#
|
||||
# @clients: A list of @VncClientInfo of all currently connected clients.
|
||||
# The list can be empty, for obvious reasons.
|
||||
#
|
||||
# @auth: The current authentication type used by the server
|
||||
#
|
||||
# @vencrypt: #optional The vencrypt sub authentication type used by the server,
|
||||
# only specified in case auth == vencrypt.
|
||||
#
|
||||
# @display: #optional The display device the vnc server is linked to.
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
{ 'type': 'VncInfo2',
|
||||
'data': { 'id' : 'str',
|
||||
'server' : ['VncBasicInfo'],
|
||||
'clients' : ['VncClientInfo'],
|
||||
'auth' : 'VncPrimaryAuth',
|
||||
'*vencrypt' : 'VncVencryptSubAuth',
|
||||
'*display' : 'str' } }
|
||||
|
||||
##
|
||||
# @query-vnc:
|
||||
#
|
||||
@@ -761,6 +821,17 @@
|
||||
##
|
||||
{ 'command': 'query-vnc', 'returns': 'VncInfo' }
|
||||
|
||||
##
|
||||
# @query-vnc-servers:
|
||||
#
|
||||
# Returns a list of vnc servers. The list can be empty.
|
||||
#
|
||||
# Returns: a list of @VncInfo2
|
||||
#
|
||||
# Since: 2.3
|
||||
##
|
||||
{ 'command': 'query-vnc-servers', 'returns': ['VncInfo2'] }
|
||||
|
||||
##
|
||||
# @SpiceBasicInfo
|
||||
#
|
||||
|
||||
@@ -2867,6 +2867,11 @@ EQMP
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_vnc,
|
||||
},
|
||||
{
|
||||
.name = "query-vnc-servers",
|
||||
.args_type = "",
|
||||
.mhandler.cmd_new = qmp_marshal_input_query_vnc_servers,
|
||||
},
|
||||
|
||||
SQMP
|
||||
query-spice
|
||||
|
||||
@@ -368,7 +368,20 @@ void qmp_change_vnc_password(const char *password, Error **errp)
|
||||
|
||||
static void qmp_change_vnc_listen(const char *target, Error **errp)
|
||||
{
|
||||
vnc_display_open(NULL, target, errp);
|
||||
QemuOptsList *olist = qemu_find_opts("vnc");
|
||||
QemuOpts *opts;
|
||||
|
||||
if (strstr(target, "id=")) {
|
||||
error_setg(errp, "id not supported");
|
||||
return;
|
||||
}
|
||||
|
||||
opts = qemu_opts_find(olist, "default");
|
||||
if (opts) {
|
||||
qemu_opts_del(opts);
|
||||
}
|
||||
opts = vnc_parse_func(target);
|
||||
vnc_display_open("default", errp);
|
||||
}
|
||||
|
||||
static void qmp_change_vnc(const char *target, bool has_arg, const char *arg,
|
||||
|
||||
@@ -150,7 +150,10 @@ typedef enum VncSharePolicy {
|
||||
struct VncDisplay
|
||||
{
|
||||
QTAILQ_HEAD(, VncState) clients;
|
||||
int num_connecting;
|
||||
int num_shared;
|
||||
int num_exclusive;
|
||||
int connections_limit;
|
||||
VncSharePolicy share_policy;
|
||||
int lsock;
|
||||
#ifdef CONFIG_VNC_WS
|
||||
@@ -171,6 +174,8 @@ struct VncDisplay
|
||||
struct VncSurface guest; /* guest visible surface (aka ds->surface) */
|
||||
pixman_image_t *server; /* vnc server surface */
|
||||
|
||||
const char *id;
|
||||
QTAILQ_ENTRY(VncDisplay) next;
|
||||
char *display;
|
||||
char *password;
|
||||
time_t expires;
|
||||
|
||||
@@ -158,9 +158,6 @@ int smp_cpus = 1;
|
||||
int max_cpus = 0;
|
||||
int smp_cores = 1;
|
||||
int smp_threads = 1;
|
||||
#ifdef CONFIG_VNC
|
||||
const char *vnc_display;
|
||||
#endif
|
||||
int acpi_enabled = 1;
|
||||
int no_hpet = 0;
|
||||
int fd_bootchk = 1;
|
||||
@@ -2002,16 +1999,12 @@ static DisplayType select_display(const char *p)
|
||||
#endif
|
||||
} else if (strstart(p, "vnc", &opts)) {
|
||||
#ifdef CONFIG_VNC
|
||||
display_remote++;
|
||||
|
||||
if (*opts) {
|
||||
const char *nextopt;
|
||||
|
||||
if (strstart(opts, "=", &nextopt)) {
|
||||
vnc_display = nextopt;
|
||||
if (*opts == '=') {
|
||||
display_remote++;
|
||||
if (vnc_parse_func(opts+1) == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (!vnc_display) {
|
||||
} else {
|
||||
fprintf(stderr, "VNC requires a display argument vnc=<display>\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -3479,7 +3472,9 @@ int main(int argc, char **argv, char **envp)
|
||||
case QEMU_OPTION_vnc:
|
||||
#ifdef CONFIG_VNC
|
||||
display_remote++;
|
||||
vnc_display = optarg;
|
||||
if (vnc_parse_func(optarg) == NULL) {
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
fprintf(stderr, "VNC support is disabled\n");
|
||||
exit(1);
|
||||
@@ -3975,7 +3970,7 @@ int main(int argc, char **argv, char **envp)
|
||||
#elif defined(CONFIG_SDL) || defined(CONFIG_COCOA)
|
||||
display_type = DT_SDL;
|
||||
#elif defined(CONFIG_VNC)
|
||||
vnc_display = "localhost:0,to=99";
|
||||
vnc_parse_func("localhost:0,to=99,id=default");
|
||||
show_vnc_port = 1;
|
||||
#else
|
||||
display_type = DT_NONE;
|
||||
@@ -4286,20 +4281,10 @@ int main(int argc, char **argv, char **envp)
|
||||
|
||||
#ifdef CONFIG_VNC
|
||||
/* init remote displays */
|
||||
if (vnc_display) {
|
||||
Error *local_err = NULL;
|
||||
vnc_display_init(ds);
|
||||
vnc_display_open(ds, vnc_display, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_report("Failed to start VNC server on `%s': %s",
|
||||
vnc_display, error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (show_vnc_port) {
|
||||
printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
|
||||
}
|
||||
qemu_opts_foreach(qemu_find_opts("vnc"), vnc_init_func, NULL, 0);
|
||||
if (show_vnc_port) {
|
||||
printf("VNC server running on `%s'\n",
|
||||
vnc_display_local_addr("default"));
|
||||
}
|
||||
#endif
|
||||
#ifdef CONFIG_SPICE
|
||||
|
||||
Reference in New Issue
Block a user