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:
Peter Maydell
2015-01-22 12:14:19 +00:00
8 changed files with 617 additions and 204 deletions
+14 -4
View File
@@ -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
View File
@@ -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
View File
@@ -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
#
+5
View File
@@ -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
+14 -1
View File
@@ -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,
+484 -162
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -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;
+13 -28
View File
@@ -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