提交 8cf36489 编写于 作者: G Gerd Hoffmann

vnc: implement shared flag handling.

VNC clients send a shared flag in the client init message.  Up to now
qemu completely ignores this.  This patch implements shared flag
handling.  It comes with three policies:  By default qemu behaves as one
would expect:  Asking for a exclusive access grants exclusive access to
the client connecting.  There is also a desktop sharing mode which
disallows exclusive connects (so one forgetting -shared wouldn't drop
everybody else) and a compatibility mode which mimics the traditional
(but non-conforming) qemu behavior.
Signed-off-by: NGerd Hoffmann <kraxel@redhat.com>
上级 e26437c2
...@@ -1095,6 +1095,19 @@ This can be really helpful to save bandwidth when playing videos. Disabling ...@@ -1095,6 +1095,19 @@ This can be really helpful to save bandwidth when playing videos. Disabling
adaptive encodings allows to restore the original static behavior of encodings adaptive encodings allows to restore the original static behavior of encodings
like Tight. like Tight.
@item share=[allow-exclusive|force-shared|ignore]
Set display sharing policy. 'allow-exclusive' allows clients to ask
for exclusive access. As suggested by the rfb spec this is
implemented by dropping other connections. Connecting multiple
clients in parallel requires all clients asking for a shared session
(vncviewer: -shared switch). This is the default. 'force-shared'
disables exclusive client access. Useful for shared desktop sessions,
where you don't want someone forgetting specify -shared disconnect
everybody else. 'ignore' completely ignores the shared flag and
allows everybody connect unconditionally. Doesn't conform to the rfb
spec but is traditional qemu behavior.
@end table @end table
ETEXI ETEXI
......
...@@ -47,6 +47,29 @@ static DisplayChangeListener *dcl; ...@@ -47,6 +47,29 @@ static DisplayChangeListener *dcl;
static int vnc_cursor_define(VncState *vs); static int vnc_cursor_define(VncState *vs);
static void vnc_set_share_mode(VncState *vs, VncShareMode mode)
{
#ifdef _VNC_DEBUG
static const char *mn[] = {
[0] = "undefined",
[VNC_SHARE_MODE_CONNECTING] = "connecting",
[VNC_SHARE_MODE_SHARED] = "shared",
[VNC_SHARE_MODE_EXCLUSIVE] = "exclusive",
[VNC_SHARE_MODE_DISCONNECTED] = "disconnected",
};
fprintf(stderr, "%s/%d: %s -> %s\n", __func__,
vs->csock, mn[vs->share_mode], mn[mode]);
#endif
if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
vs->vd->num_exclusive--;
}
vs->share_mode = mode;
if (vs->share_mode == VNC_SHARE_MODE_EXCLUSIVE) {
vs->vd->num_exclusive++;
}
}
static char *addr_to_string(const char *format, static char *addr_to_string(const char *format,
struct sockaddr_storage *sa, struct sockaddr_storage *sa,
socklen_t salen) { socklen_t salen) {
...@@ -997,6 +1020,7 @@ static void vnc_disconnect_start(VncState *vs) ...@@ -997,6 +1020,7 @@ static void vnc_disconnect_start(VncState *vs)
{ {
if (vs->csock == -1) if (vs->csock == -1)
return; return;
vnc_set_share_mode(vs, VNC_SHARE_MODE_DISCONNECTED);
qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
closesocket(vs->csock); closesocket(vs->csock);
vs->csock = -1; vs->csock = -1;
...@@ -2054,8 +2078,67 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) ...@@ -2054,8 +2078,67 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)
static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) static int protocol_client_init(VncState *vs, uint8_t *data, size_t len)
{ {
char buf[1024]; char buf[1024];
VncShareMode mode;
int size; int size;
mode = data[0] ? VNC_SHARE_MODE_SHARED : VNC_SHARE_MODE_EXCLUSIVE;
switch (vs->vd->share_policy) {
case VNC_SHARE_POLICY_IGNORE:
/*
* Ignore the shared flag. Nothing to do here.
*
* Doesn't conform to the rfb spec but is traditional qemu
* behavior, thus left here as option for compatibility
* reasons.
*/
break;
case VNC_SHARE_POLICY_ALLOW_EXCLUSIVE:
/*
* Policy: Allow clients ask for exclusive access.
*
* Implementation: When a client asks for exclusive access,
* disconnect all others. Shared connects are allowed as long
* as no exclusive connection exists.
*
* This is how the rfb spec suggests to handle the shared flag.
*/
if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
VncState *client;
QTAILQ_FOREACH(client, &vs->vd->clients, next) {
if (vs == client) {
continue;
}
if (client->share_mode != VNC_SHARE_MODE_EXCLUSIVE &&
client->share_mode != VNC_SHARE_MODE_SHARED) {
continue;
}
vnc_disconnect_start(client);
}
}
if (mode == VNC_SHARE_MODE_SHARED) {
if (vs->vd->num_exclusive > 0) {
vnc_disconnect_start(vs);
return 0;
}
}
break;
case VNC_SHARE_POLICY_FORCE_SHARED:
/*
* Policy: Shared connects only.
* Implementation: Disallow clients asking for exclusive access.
*
* Useful for shared desktop sessions where you don't want
* someone forgetting to say -shared when running the vnc
* client disconnect everybody else.
*/
if (mode == VNC_SHARE_MODE_EXCLUSIVE) {
vnc_disconnect_start(vs);
return 0;
}
break;
}
vnc_set_share_mode(vs, mode);
vs->client_width = ds_get_width(vs->ds); vs->client_width = ds_get_width(vs->ds);
vs->client_height = ds_get_height(vs->ds); vs->client_height = ds_get_height(vs->ds);
vnc_write_u16(vs, vs->client_width); vnc_write_u16(vs, vs->client_width);
...@@ -2562,6 +2645,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth) ...@@ -2562,6 +2645,7 @@ static void vnc_connect(VncDisplay *vd, int csock, int skipauth)
vnc_client_cache_addr(vs); vnc_client_cache_addr(vs);
vnc_qmp_event(vs, QEVENT_VNC_CONNECTED); vnc_qmp_event(vs, QEVENT_VNC_CONNECTED);
vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
vs->vd = vd; vs->vd = vd;
vs->ds = vd->ds; vs->ds = vd->ds;
...@@ -2755,6 +2839,7 @@ int vnc_display_open(DisplayState *ds, const char *display) ...@@ -2755,6 +2839,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
if (!(vs->display = strdup(display))) if (!(vs->display = strdup(display)))
return -1; return -1;
vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
options = display; options = display;
while ((options = strchr(options, ','))) { while ((options = strchr(options, ','))) {
...@@ -2810,6 +2895,19 @@ int vnc_display_open(DisplayState *ds, const char *display) ...@@ -2810,6 +2895,19 @@ int vnc_display_open(DisplayState *ds, const char *display)
vs->lossy = true; vs->lossy = true;
} else if (strncmp(options, "non-adapative", 13) == 0) { } else if (strncmp(options, "non-adapative", 13) == 0) {
vs->non_adaptive = true; vs->non_adaptive = true;
} else if (strncmp(options, "share=", 6) == 0) {
if (strncmp(options+6, "ignore", 6) == 0) {
vs->share_policy = VNC_SHARE_POLICY_IGNORE;
} else if (strncmp(options+6, "allow-exclusive", 15) == 0) {
vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
} else if (strncmp(options+6, "force-shared", 12) == 0) {
vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
} else {
fprintf(stderr, "unknown vnc share= option\n");
g_free(vs->display);
vs->display = NULL;
return -1;
}
} }
} }
......
...@@ -122,9 +122,24 @@ struct VncSurface ...@@ -122,9 +122,24 @@ struct VncSurface
DisplaySurface *ds; DisplaySurface *ds;
}; };
typedef enum VncShareMode {
VNC_SHARE_MODE_CONNECTING = 1,
VNC_SHARE_MODE_SHARED,
VNC_SHARE_MODE_EXCLUSIVE,
VNC_SHARE_MODE_DISCONNECTED,
} VncShareMode;
typedef enum VncSharePolicy {
VNC_SHARE_POLICY_IGNORE = 1,
VNC_SHARE_POLICY_ALLOW_EXCLUSIVE,
VNC_SHARE_POLICY_FORCE_SHARED,
} VncSharePolicy;
struct VncDisplay struct VncDisplay
{ {
QTAILQ_HEAD(, VncState) clients; QTAILQ_HEAD(, VncState) clients;
int num_exclusive;
VncSharePolicy share_policy;
QEMUTimer *timer; QEMUTimer *timer;
int timer_interval; int timer_interval;
int lsock; int lsock;
...@@ -250,6 +265,7 @@ struct VncState ...@@ -250,6 +265,7 @@ struct VncState
int last_y; int last_y;
int client_width; int client_width;
int client_height; int client_height;
VncShareMode share_mode;
uint32_t vnc_encoding; uint32_t vnc_encoding;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册