summaryrefslogtreecommitdiff
path: root/ui
diff options
context:
space:
mode:
authorSeokYeon Hwang <syeon.hwang@samsung.com>2016-12-20 10:13:15 +0900
committerSeokYeon Hwang <syeon.hwang@samsung.com>2016-12-20 10:13:15 +0900
commitdc36664b156b6aa2b55f2bca5fd0c643b6417ddb (patch)
treebb319daf3cd759c2d91dd541bb2ee24d8ca4ee1a /ui
parent100d9fdc18f28d813f9d22025d783a7cdcc4bb4b (diff)
parent6a928d25b6d8bc3729c3d28326c6db13b9481059 (diff)
downloadqemu-dc36664b156b6aa2b55f2bca5fd0c643b6417ddb.tar.gz
qemu-dc36664b156b6aa2b55f2bca5fd0c643b6417ddb.tar.bz2
qemu-dc36664b156b6aa2b55f2bca5fd0c643b6417ddb.zip
Merge tag 'v2.8.0-rc4' into develop
v2.8.0-rc4 release Change-Id: I0158b5078d1af545dc32a51f10d2f8f0b96543a6 Signed-off-by: SeokYeon Hwang <syeon.hwang@samsung.com>
Diffstat (limited to 'ui')
-rw-r--r--ui/cocoa.m123
-rw-r--r--ui/console.c40
-rw-r--r--ui/curses.c24
-rw-r--r--ui/gtk.c44
-rw-r--r--ui/input-linux.c15
-rw-r--r--ui/spice-core.c2
-rw-r--r--ui/spice-display.c92
-rw-r--r--ui/vnc-auth-vencrypt.c1
-rw-r--r--ui/vnc-enc-tight.c6
-rw-r--r--ui/vnc-ws.c5
-rw-r--r--ui/vnc.c423
-rw-r--r--ui/vnc.h7
12 files changed, 486 insertions, 296 deletions
diff --git a/ui/cocoa.m b/ui/cocoa.m
index 8fe527b875..e508bb12ca 100644
--- a/ui/cocoa.m
+++ b/ui/cocoa.m
@@ -33,6 +33,7 @@
#include "sysemu/sysemu.h"
#include "qmp-commands.h"
#include "sysemu/blockdev.h"
+#include "qemu-version.h"
#include <Carbon/Carbon.h>
#ifndef MAC_OS_X_VERSION_10_5
@@ -63,7 +64,7 @@ typedef struct {
int bitsPerPixel;
} QEMUScreen;
-NSWindow *normalWindow;
+NSWindow *normalWindow, *about_window;
static DisplayChangeListener *dcl;
static int last_buttons;
@@ -670,7 +671,9 @@ QemuCocoaView *cocoaView;
case NSLeftMouseUp:
mouse_event = true;
if (!isMouseGrabbed && [self screenContainsPoint:p]) {
- [self grabMouse];
+ if([[self window] isKeyWindow]) {
+ [self grabMouse];
+ }
}
break;
case NSRightMouseUp:
@@ -811,7 +814,6 @@ QemuCocoaView *cocoaView;
- (void)doToggleFullScreen:(id)sender;
- (void)toggleFullScreen:(id)sender;
- (void)showQEMUDoc:(id)sender;
-- (void)showQEMUTec:(id)sender;
- (void)zoomToFit:(id) sender;
- (void)displayConsole:(id)sender;
- (void)pauseQEMU:(id)sender;
@@ -824,6 +826,8 @@ QemuCocoaView *cocoaView;
- (void)changeDeviceMedia:(id)sender;
- (BOOL)verifyQuit;
- (void)openDocumentation:(NSString *)filename;
+- (IBAction) do_about_menu_item: (id) sender;
+- (void)make_about_window;
@end
@implementation QemuCocoaAppController
@@ -876,6 +880,7 @@ QemuCocoaView *cocoaView;
supportedImageFileTypes = [NSArray arrayWithObjects: @"img", @"iso", @"dmg",
@"qcow", @"qcow2", @"cloop", @"vmdk", @"cdr",
nil];
+ [self make_about_window];
}
return self;
}
@@ -992,13 +997,6 @@ QemuCocoaView *cocoaView;
[self openDocumentation: @"qemu-doc.html"];
}
-- (void)showQEMUTec:(id)sender
-{
- COCOA_DEBUG("QemuCocoaAppController: showQEMUTec\n");
-
- [self openDocumentation: @"qemu-tech.html"];
-}
-
/* Stretches video to fit host monitor size */
- (void)zoomToFit:(id) sender
{
@@ -1079,7 +1077,8 @@ QemuCocoaView *cocoaView;
}
Error *err = NULL;
- qmp_eject([drive cStringUsingEncoding: NSASCIIStringEncoding], false, false, &err);
+ qmp_eject(true, [drive cStringUsingEncoding: NSASCIIStringEncoding],
+ false, NULL, false, false, &err);
handleAnyDeviceErrors(err);
}
@@ -1112,8 +1111,10 @@ QemuCocoaView *cocoaView;
}
Error *err = NULL;
- qmp_blockdev_change_medium([drive cStringUsingEncoding:
+ qmp_blockdev_change_medium(true,
+ [drive cStringUsingEncoding:
NSASCIIStringEncoding],
+ false, NULL,
[file cStringUsingEncoding:
NSASCIIStringEncoding],
true, "raw",
@@ -1138,6 +1139,101 @@ QemuCocoaView *cocoaView;
}
}
+/* The action method for the About menu item */
+- (IBAction) do_about_menu_item: (id) sender
+{
+ [about_window makeKeyAndOrderFront: nil];
+}
+
+/* Create and display the about dialog */
+- (void)make_about_window
+{
+ /* Make the window */
+ int x = 0, y = 0, about_width = 400, about_height = 200;
+ NSRect window_rect = NSMakeRect(x, y, about_width, about_height);
+ about_window = [[NSWindow alloc] initWithContentRect:window_rect
+ styleMask:NSTitledWindowMask | NSClosableWindowMask |
+ NSMiniaturizableWindowMask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ [about_window setTitle: @"About"];
+ [about_window setReleasedWhenClosed: NO];
+ [about_window center];
+ NSView *superView = [about_window contentView];
+
+ /* Create the dimensions of the picture */
+ int picture_width = 80, picture_height = 80;
+ x = (about_width - picture_width)/2;
+ y = about_height - picture_height - 10;
+ NSRect picture_rect = NSMakeRect(x, y, picture_width, picture_height);
+
+ /* Get the path to the QEMU binary */
+ NSString *binary_name = [NSString stringWithCString: gArgv[0]
+ encoding: NSASCIIStringEncoding];
+ binary_name = [binary_name lastPathComponent];
+ NSString *program_path = [[NSString alloc] initWithFormat: @"%@/%@",
+ [[NSBundle mainBundle] bundlePath], binary_name];
+
+ /* Make the picture of QEMU */
+ NSImageView *picture_view = [[NSImageView alloc] initWithFrame:
+ picture_rect];
+ NSImage *qemu_image = [[NSWorkspace sharedWorkspace] iconForFile:
+ program_path];
+ [picture_view setImage: qemu_image];
+ [picture_view setImageScaling: NSImageScaleProportionallyUpOrDown];
+ [superView addSubview: picture_view];
+
+ /* Make the name label */
+ x = 0;
+ y = y - 25;
+ int name_width = about_width, name_height = 20;
+ NSRect name_rect = NSMakeRect(x, y, name_width, name_height);
+ NSTextField *name_label = [[NSTextField alloc] initWithFrame: name_rect];
+ [name_label setEditable: NO];
+ [name_label setBezeled: NO];
+ [name_label setDrawsBackground: NO];
+ [name_label setAlignment: NSCenterTextAlignment];
+ NSString *qemu_name = [[NSString alloc] initWithCString: gArgv[0]
+ encoding: NSASCIIStringEncoding];
+ qemu_name = [qemu_name lastPathComponent];
+ [name_label setStringValue: qemu_name];
+ [superView addSubview: name_label];
+
+ /* Set the version label's attributes */
+ x = 0;
+ y = 50;
+ int version_width = about_width, version_height = 20;
+ NSRect version_rect = NSMakeRect(x, y, version_width, version_height);
+ NSTextField *version_label = [[NSTextField alloc] initWithFrame:
+ version_rect];
+ [version_label setEditable: NO];
+ [version_label setBezeled: NO];
+ [version_label setAlignment: NSCenterTextAlignment];
+ [version_label setDrawsBackground: NO];
+
+ /* Create the version string*/
+ NSString *version_string;
+ version_string = [[NSString alloc] initWithFormat:
+ @"QEMU emulator version %s%s", QEMU_VERSION, QEMU_PKGVERSION];
+ [version_label setStringValue: version_string];
+ [superView addSubview: version_label];
+
+ /* Make copyright label */
+ x = 0;
+ y = 35;
+ int copyright_width = about_width, copyright_height = 20;
+ NSRect copyright_rect = NSMakeRect(x, y, copyright_width, copyright_height);
+ NSTextField *copyright_label = [[NSTextField alloc] initWithFrame:
+ copyright_rect];
+ [copyright_label setEditable: NO];
+ [copyright_label setBezeled: NO];
+ [copyright_label setDrawsBackground: NO];
+ [copyright_label setAlignment: NSCenterTextAlignment];
+ [copyright_label setStringValue: [NSString stringWithFormat: @"%s",
+ QEMU_COPYRIGHT]];
+ [superView addSubview: copyright_label];
+}
+
@end
#ifdef CONFIG_MARU
@@ -1189,7 +1285,7 @@ int main (int argc, const char * argv[]) {
// Application menu
menu = [[NSMenu alloc] initWithTitle:@""];
- [menu addItemWithTitle:@"About QEMU" action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; // About QEMU
+ [menu addItemWithTitle:@"About QEMU" action:@selector(do_about_menu_item:) keyEquivalent:@""]; // About QEMU
[menu addItem:[NSMenuItem separatorItem]]; //Separator
[menu addItemWithTitle:@"Hide QEMU" action:@selector(hide:) keyEquivalent:@"h"]; //Hide QEMU
menuItem = (NSMenuItem *)[menu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; // Hide Others
@@ -1235,7 +1331,6 @@ int main (int argc, const char * argv[]) {
// Help menu
menu = [[NSMenu alloc] initWithTitle:@"Help"];
[menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Documentation" action:@selector(showQEMUDoc:) keyEquivalent:@"?"] autorelease]]; // QEMU Help
- [menu addItem: [[[NSMenuItem alloc] initWithTitle:@"QEMU Technology" action:@selector(showQEMUTec:) keyEquivalent:@""] autorelease]]; // QEMU Help
menuItem = [[[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""] autorelease];
[menuItem setSubmenu:menu];
[[NSApp mainMenu] addItem:menuItem];
diff --git a/ui/console.c b/ui/console.c
index ee270d760f..719e712775 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -130,6 +130,7 @@ struct QemuConsole {
DisplaySurface *surface;
int dcls;
DisplayChangeListener *gl;
+ bool gl_block;
/* Graphic console state. */
Object *device;
@@ -271,10 +272,10 @@ void graphic_hw_update(QemuConsole *con)
void graphic_hw_gl_block(QemuConsole *con, bool block)
{
- if (!con) {
- con = active_console;
- }
- if (con && con->hw_ops->gl_block) {
+ assert(con != NULL);
+
+ con->gl_block = block;
+ if (con->hw_ops->gl_block) {
con->hw_ops->gl_block(con->hw, block);
}
}
@@ -1089,6 +1090,7 @@ static void kbd_send_chars(void *opaque)
void kbd_put_keysym_console(QemuConsole *s, int keysym)
{
uint8_t buf[16], *q;
+ CharBackend *be;
int c;
if (!s || (s->console_type == GRAPHIC_CONSOLE))
@@ -1131,7 +1133,8 @@ void kbd_put_keysym_console(QemuConsole *s, int keysym)
if (s->echo) {
console_puts(s->chr, buf, q - buf);
}
- if (s->chr->chr_read) {
+ be = s->chr->be;
+ if (be && be->chr_read) {
qemu_fifo_write(&s->out_fifo, buf, q - buf);
kbd_send_chars(s);
}
@@ -1149,6 +1152,7 @@ static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
[Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP,
[Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN,
[Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
+ [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
};
bool kbd_put_qcode_console(QemuConsole *s, int qcode)
@@ -1892,6 +1896,12 @@ bool qemu_console_is_fixedsize(QemuConsole *con)
return con && (con->console_type != TEXT_CONSOLE);
}
+bool qemu_console_is_gl_blocked(QemuConsole *con)
+{
+ assert(con != NULL);
+ return con->gl_block;
+}
+
char *qemu_console_get_label(QemuConsole *con)
{
if (con->console_type == GRAPHIC_CONSOLE) {
@@ -2039,8 +2049,6 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
}
qemu_chr_be_generic_open(chr);
- if (chr->init)
- chr->init(chr);
}
static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
@@ -2085,10 +2093,6 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
s->chr = chr;
chr->opaque = s;
chr->chr_set_echo = text_console_set_echo;
- /* console/chardev init sometimes completes elsewhere in a 2nd
- * stage, so defer OPENED events until they are fully initialized
- */
- chr->explicit_be_open = true;
if (display_state) {
text_console_do_init(chr, display_state);
@@ -2099,8 +2103,13 @@ static CharDriverState *text_console_init(ChardevVC *vc, Error **errp)
static VcHandler *vc_handler = text_console_init;
static CharDriverState *vc_init(const char *id, ChardevBackend *backend,
- ChardevReturn *ret, Error **errp)
+ ChardevReturn *ret, bool *be_opened,
+ Error **errp)
{
+ /* console/chardev init sometimes completes elsewhere in a 2nd
+ * stage, so defer OPENED events until they are fully initialized
+ */
+ *be_opened = false;
return vc_handler(backend->u.vc.data, errp);
}
@@ -2114,6 +2123,13 @@ void qemu_console_resize(QemuConsole *s, int width, int height)
DisplaySurface *surface;
assert(s->console_type == GRAPHIC_CONSOLE);
+
+ if (s->surface &&
+ pixman_image_get_width(s->surface->image) == width &&
+ pixman_image_get_height(s->surface->image) == height) {
+ return;
+ }
+
surface = qemu_create_displaysurface(width, height);
dpy_gfx_replace_surface(s, surface);
}
diff --git a/ui/curses.c b/ui/curses.c
index b47558956c..2e132a7bfa 100644
--- a/ui/curses.c
+++ b/ui/curses.c
@@ -181,7 +181,7 @@ static kbd_layout_t *kbd_layout = NULL;
static void curses_refresh(DisplayChangeListener *dcl)
{
- int chr, nextchr, keysym, keycode, keycode_alt;
+ int chr, keysym, keycode, keycode_alt;
curses_winch_check();
@@ -195,15 +195,9 @@ static void curses_refresh(DisplayChangeListener *dcl)
graphic_hw_text_update(NULL, screen);
- nextchr = ERR;
while (1) {
/* while there are any pending key strokes to process */
- if (nextchr == ERR)
- chr = getch();
- else {
- chr = nextchr;
- nextchr = ERR;
- }
+ chr = getch();
if (chr == ERR)
break;
@@ -224,13 +218,12 @@ static void curses_refresh(DisplayChangeListener *dcl)
/* alt key */
if (keycode == 1) {
- nextchr = getch();
+ int nextchr = getch();
if (nextchr != ERR) {
chr = nextchr;
keycode_alt = ALT;
- keycode = curses2keycode[nextchr];
- nextchr = ERR;
+ keycode = curses2keycode[chr];
if (keycode != -1) {
keycode |= ALT;
@@ -317,7 +310,10 @@ static void curses_refresh(DisplayChangeListener *dcl)
qemu_input_event_send_key_delay(0);
}
} else {
- keysym = curses2qemu[chr];
+ keysym = -1;
+ if (chr < CURSES_KEYS) {
+ keysym = curses2qemu[chr];
+ }
if (keysym == -1)
keysym = chr;
@@ -373,10 +369,10 @@ static void curses_setup(void)
/* ACS_* is not constant. So, we can't initialize statically. */
vga_to_curses['\0'] = ' ';
vga_to_curses[0x04] = ACS_DIAMOND;
- vga_to_curses[0x0a] = ACS_RARROW;
- vga_to_curses[0x0b] = ACS_LARROW;
vga_to_curses[0x18] = ACS_UARROW;
vga_to_curses[0x19] = ACS_DARROW;
+ vga_to_curses[0x1a] = ACS_RARROW;
+ vga_to_curses[0x1b] = ACS_LARROW;
vga_to_curses[0x9c] = ACS_STERLING;
vga_to_curses[0xb0] = ACS_BOARD;
vga_to_curses[0xb1] = ACS_CKBOARD;
diff --git a/ui/gtk.c b/ui/gtk.c
index 58d20eed62..a216216d8b 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -94,7 +94,7 @@
#define GDK_IS_WIN32_DISPLAY(dpy) (dpy == dpy)
#endif
-#ifndef GDK_KEY_0
+#if !GTK_CHECK_VERSION(2, 22, 0)
#define GDK_KEY_0 GDK_0
#define GDK_KEY_1 GDK_1
#define GDK_KEY_2 GDK_2
@@ -104,6 +104,7 @@
#define GDK_KEY_plus GDK_plus
#define GDK_KEY_minus GDK_minus
#define GDK_KEY_Pause GDK_Pause
+#define GDK_KEY_Delete GDK_Delete
#endif
/* Some older mingw versions lack this constant or have
@@ -912,9 +913,28 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
if (!qemu_input_is_absolute() && s->ptr_owner == vc) {
GdkScreen *screen = gtk_widget_get_screen(vc->gfx.drawing_area);
+ int screen_width, screen_height;
+
int x = (int)motion->x_root;
int y = (int)motion->y_root;
+#if GTK_CHECK_VERSION(3, 22, 0)
+ {
+ GdkDisplay *dpy = gtk_widget_get_display(widget);
+ GdkWindow *win = gtk_widget_get_window(widget);
+ GdkMonitor *monitor = gdk_display_get_monitor_at_window(dpy, win);
+ GdkRectangle geometry;
+ gdk_monitor_get_geometry(monitor, &geometry);
+ screen_width = geometry.width;
+ screen_height = geometry.height;
+ }
+#else
+ {
+ screen_width = gdk_screen_get_width(screen);
+ screen_height = gdk_screen_get_height(screen);
+ }
+#endif
+
/* In relative mode check to see if client pointer hit
* one of the screen edges, and if so move it back by
* 200 pixels. This is important because the pointer
@@ -928,10 +948,10 @@ static gboolean gd_motion_event(GtkWidget *widget, GdkEventMotion *motion,
if (y == 0) {
y += 200;
}
- if (x == (gdk_screen_get_width(screen) - 1)) {
+ if (x == (screen_width - 1)) {
x -= 200;
}
- if (y == (gdk_screen_get_height(screen) - 1)) {
+ if (y == (screen_height - 1)) {
y -= 200;
}
@@ -1051,7 +1071,9 @@ static gboolean gd_text_key_down(GtkWidget *widget,
VirtualConsole *vc = opaque;
QemuConsole *con = vc->gfx.dcl.con;
- if (key->length) {
+ if (key->keyval == GDK_KEY_Delete) {
+ kbd_put_qcode_console(con, Q_KEY_CODE_DELETE);
+ } else if (key->length) {
kbd_put_string_console(con, key->string, key->length);
} else {
int num = gd_map_keycode(vc->s, gtk_widget_get_display(widget),
@@ -1559,6 +1581,9 @@ static void gd_change_page(GtkNotebook *nb, gpointer arg1, guint arg2,
TRUE);
}
gtk_widget_set_sensitive(s->grab_item, on_vga);
+#ifdef CONFIG_VTE
+ gtk_widget_set_sensitive(s->copy_item, vc->type == GD_VC_VTE);
+#endif
gd_update_windowsize(vc);
gd_update_cursor(vc);
@@ -1685,9 +1710,6 @@ static CharDriverState *gd_vc_handler(ChardevVC *vc, Error **errp)
/* Temporary, until gd_vc_vte_init runs. */
chr->opaque = g_new0(VirtualConsole, 1);
- /* defer OPENED events until our vc is fully initialized */
- chr->explicit_be_open = true;
-
vcs[nb_vcs++] = chr;
return chr;
@@ -1789,9 +1811,6 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
gtk_label_new(vc->label));
qemu_chr_be_generic_open(vc->vte.chr);
- if (vc->vte.chr->init) {
- vc->vte.chr->init(vc->vte.chr);
- }
return group;
}
@@ -2230,6 +2249,11 @@ void gtk_display_init(DisplayState *ds, bool full_screen, bool grab_on_hover)
}
#endif
+#ifdef CONFIG_VTE
+ gtk_widget_set_sensitive(s->copy_item,
+ gd_vc_find_current(s)->type == GD_VC_VTE);
+#endif
+
if (full_screen) {
gtk_menu_item_activate(GTK_MENU_ITEM(s->full_screen_item));
}
diff --git a/ui/input-linux.c b/ui/input-linux.c
index 0e230ce699..f345317794 100644
--- a/ui/input-linux.c
+++ b/ui/input-linux.c
@@ -347,7 +347,8 @@ static void input_linux_event(void *opaque)
static void input_linux_complete(UserCreatable *uc, Error **errp)
{
InputLinux *il = INPUT_LINUX(uc);
- uint8_t evtmap, relmap, absmap, keymap[KEY_CNT / 8];
+ uint8_t evtmap, relmap, absmap;
+ uint8_t keymap[KEY_CNT / 8], keystate[KEY_CNT / 8];
unsigned int i;
int rc, ver;
@@ -394,6 +395,7 @@ static void input_linux_complete(UserCreatable *uc, Error **errp)
if (evtmap & (1 << EV_KEY)) {
memset(keymap, 0, sizeof(keymap));
rc = ioctl(il->fd, EVIOCGBIT(EV_KEY, sizeof(keymap)), keymap);
+ rc = ioctl(il->fd, EVIOCGKEY(sizeof(keystate)), keystate);
for (i = 0; i < KEY_CNT; i++) {
if (keymap[i / 8] & (1 << (i % 8))) {
if (linux_is_button(i)) {
@@ -401,12 +403,21 @@ static void input_linux_complete(UserCreatable *uc, Error **errp)
} else {
il->num_keys++;
}
+ if (keystate[i / 8] & (1 << (i % 8))) {
+ il->keydown[i] = true;
+ il->keycount++;
+ }
}
}
}
qemu_set_fd_handler(il->fd, input_linux_event, NULL, il);
- input_linux_toggle_grab(il);
+ if (il->keycount) {
+ /* delay grab until all keys are released */
+ il->grab_request = true;
+ } else {
+ input_linux_toggle_grab(il);
+ }
QTAILQ_INSERT_TAIL(&inputs, il, next);
il->initialized = true;
return;
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 34df86b122..a61c7fbe4a 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -805,7 +805,7 @@ void qemu_spice_init(void)
qemu_opt_foreach(opts, add_channel, &tls_port, NULL);
spice_server_set_name(spice_server, qemu_name);
- spice_server_set_uuid(spice_server, qemu_uuid);
+ spice_server_set_uuid(spice_server, (unsigned char *)&qemu_uuid);
seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0);
spice_server_set_seamless_migration(spice_server, seamless_migration);
diff --git a/ui/spice-display.c b/ui/spice-display.c
index eb93f44942..4ad13fcd40 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -889,6 +889,74 @@ static void qemu_spice_gl_block_timer(void *opaque)
fprintf(stderr, "WARNING: spice: no gl-draw-done within one second\n");
}
+static void spice_gl_refresh(DisplayChangeListener *dcl)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+ uint64_t cookie;
+
+ if (!ssd->ds || qemu_console_is_gl_blocked(ssd->dcl.con)) {
+ return;
+ }
+
+ graphic_hw_update(dcl->con);
+ if (ssd->gl_updates && ssd->have_surface) {
+ qemu_spice_gl_block(ssd, true);
+ cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
+ spice_qxl_gl_draw_async(&ssd->qxl, 0, 0,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds),
+ cookie);
+ ssd->gl_updates = 0;
+ }
+}
+
+static void spice_gl_update(DisplayChangeListener *dcl,
+ int x, int y, int w, int h)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+
+ surface_gl_update_texture(ssd->gls, ssd->ds, x, y, w, h);
+ ssd->gl_updates++;
+}
+
+static void spice_gl_switch(DisplayChangeListener *dcl,
+ struct DisplaySurface *new_surface)
+{
+ SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
+ EGLint stride, fourcc;
+ int fd;
+
+ if (ssd->ds) {
+ surface_gl_destroy_texture(ssd->gls, ssd->ds);
+ }
+ ssd->ds = new_surface;
+ if (ssd->ds) {
+ surface_gl_create_texture(ssd->gls, ssd->ds);
+ fd = egl_get_fd_for_texture(ssd->ds->texture,
+ &stride, &fourcc);
+ if (fd < 0) {
+ surface_gl_destroy_texture(ssd->gls, ssd->ds);
+ return;
+ }
+
+ dprint(1, "%s: %dx%d (stride %d/%d, fourcc 0x%x)\n", __func__,
+ surface_width(ssd->ds), surface_height(ssd->ds),
+ surface_stride(ssd->ds), stride, fourcc);
+
+ /* note: spice server will close the fd */
+ spice_qxl_gl_scanout(&ssd->qxl, fd,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds),
+ stride, fourcc, false);
+ ssd->have_surface = true;
+ ssd->have_scanout = false;
+
+ qemu_spice_gl_monitor_config(ssd, 0, 0,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds));
+ }
+}
+
static QEMUGLContext qemu_spice_gl_create_context(DisplayChangeListener *dcl,
QEMUGLParams *params)
{
@@ -926,6 +994,8 @@ static void qemu_spice_gl_scanout(DisplayChangeListener *dcl,
/* note: spice server will close the fd */
spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
stride, fourcc, y_0_top);
+ ssd->have_surface = false;
+ ssd->have_scanout = (tex_id != 0);
qemu_spice_gl_monitor_config(ssd, x, y, w, h);
}
@@ -936,6 +1006,10 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
uint64_t cookie;
+ if (!ssd->have_scanout) {
+ return;
+ }
+
dprint(2, "%s: %dx%d+%d+%d\n", __func__, w, h, x, y);
qemu_spice_gl_block(ssd, true);
cookie = (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_GL_DRAW_DONE, 0);
@@ -943,13 +1017,13 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
}
static const DisplayChangeListenerOps display_listener_gl_ops = {
- .dpy_name = "spice-egl",
- .dpy_gfx_update = display_update,
- .dpy_gfx_switch = display_switch,
- .dpy_gfx_check_format = qemu_pixman_check_format,
- .dpy_refresh = display_refresh,
- .dpy_mouse_set = display_mouse_set,
- .dpy_cursor_define = display_mouse_define,
+ .dpy_name = "spice-egl",
+ .dpy_gfx_update = spice_gl_update,
+ .dpy_gfx_switch = spice_gl_switch,
+ .dpy_gfx_check_format = console_gl_check_format,
+ .dpy_refresh = spice_gl_refresh,
+ .dpy_mouse_set = display_mouse_set,
+ .dpy_cursor_define = display_mouse_define,
.dpy_gl_ctx_create = qemu_spice_gl_create_context,
.dpy_gl_ctx_destroy = qemu_egl_destroy_context,
@@ -972,10 +1046,12 @@ static void qemu_spice_display_init_one(QemuConsole *con)
#ifdef HAVE_SPICE_GL
if (display_opengl) {
ssd->dcl.ops = &display_listener_gl_ops;
- ssd->dmabuf_fd = -1;
ssd->gl_unblock_bh = qemu_bh_new(qemu_spice_gl_unblock_bh, ssd);
ssd->gl_unblock_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
qemu_spice_gl_block_timer, ssd);
+ ssd->gls = console_gl_init_context();
+ ssd->have_surface = false;
+ ssd->have_scanout = false;
}
#endif
ssd->dcl.con = con;
diff --git a/ui/vnc-auth-vencrypt.c b/ui/vnc-auth-vencrypt.c
index 11c8c9a819..c0c29a5119 100644
--- a/ui/vnc-auth-vencrypt.c
+++ b/ui/vnc-auth-vencrypt.c
@@ -116,6 +116,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
return 0;
}
+ qio_channel_set_name(QIO_CHANNEL(tls), "vnc-server-tls");
VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
object_unref(OBJECT(vs->ioc));
vs->ioc = QIO_CHANNEL(tls);
diff --git a/ui/vnc-enc-tight.c b/ui/vnc-enc-tight.c
index 49df85e763..1e53b1cf84 100644
--- a/ui/vnc-enc-tight.c
+++ b/ui/vnc-enc-tight.c
@@ -707,10 +707,8 @@ check_solid_tile32(VncState *vs, int x, int y, int w, int h,
static bool check_solid_tile(VncState *vs, int x, int y, int w, int h,
uint32_t* color, bool samecolor)
{
- switch (VNC_SERVER_FB_BYTES) {
- case 4:
- return check_solid_tile32(vs, x, y, w, h, color, samecolor);
- }
+ QEMU_BUILD_BUG_ON(VNC_SERVER_FB_BYTES != 4);
+ return check_solid_tile32(vs, x, y, w, h, color, samecolor);
}
static void find_best_solid_area(VncState *vs, int x, int y, int w, int h,
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index 3bac46e774..bffb484a8d 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -67,6 +67,8 @@ gboolean vncws_tls_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
return TRUE;
}
+ qio_channel_set_name(QIO_CHANNEL(tls), "vnc-ws-server-tls");
+
VNC_DEBUG("Start TLS WS handshake process\n");
object_unref(OBJECT(vs->ioc));
vs->ioc = QIO_CHANNEL(tls);
@@ -92,7 +94,7 @@ static void vncws_handshake_done(Object *source,
vnc_client_error(vs);
} else {
VNC_DEBUG("Websock handshake complete, starting VNC protocol\n");
- vnc_init_state(vs);
+ vnc_start_protocol(vs);
vs->ioc_tag = qio_channel_add_watch(
vs->ioc, G_IO_IN, vnc_client_io, vs, NULL);
}
@@ -113,6 +115,7 @@ gboolean vncws_handshake_io(QIOChannel *ioc G_GNUC_UNUSED,
}
wioc = qio_channel_websock_new_server(vs->ioc);
+ qio_channel_set_name(QIO_CHANNEL(wioc), "vnc-ws-server-websock");
object_unref(OBJECT(vs->ioc));
vs->ioc = QIO_CHANNEL(wioc);
diff --git a/ui/vnc.c b/ui/vnc.c
index d1087c93a5..2c28a59ff7 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -371,7 +371,7 @@ VncInfo *qmp_query_vnc(Error **errp)
VncDisplay *vd = vnc_display_find(NULL);
SocketAddress *addr = NULL;
- if (vd == NULL || !vd->enabled) {
+ if (vd == NULL || !vd->lsock) {
info->enabled = false;
} else {
info->enabled = true;
@@ -911,6 +911,10 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl,
}
}
+ if (!vd->server) {
+ /* no client connected */
+ return;
+ }
/* do bitblit op on the local surface too */
pitch = vnc_server_fb_stride(vd);
src_row = vnc_server_fb_ptr(vd, src_x, src_y);
@@ -1218,13 +1222,13 @@ void vnc_disconnect_finish(VncState *vs)
audio_del(vs);
vnc_release_modifiers(vs);
- if (vs->initialized) {
- QTAILQ_REMOVE(&vs->vd->clients, vs, next);
+ if (vs->mouse_mode_notifier.notify != NULL) {
qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
- if (QTAILQ_EMPTY(&vs->vd->clients)) {
- /* last client gone */
- vnc_update_server_surface(vs->vd);
- }
+ }
+ QTAILQ_REMOVE(&vs->vd->clients, vs, next);
+ if (QTAILQ_EMPTY(&vs->vd->clients)) {
+ /* last client gone */
+ vnc_update_server_surface(vs->vd);
}
if (vs->vd->lock_key_sync)
@@ -2974,6 +2978,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
bool skipauth, bool websocket)
{
VncState *vs = g_new0(VncState, 1);
+ bool first_client = QTAILQ_EMPTY(&vd->clients);
int i;
vs->sioc = sioc;
@@ -3025,7 +3030,7 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
qio_channel_set_blocking(vs->ioc, false, NULL);
if (websocket) {
vs->websocket = 1;
- if (vd->ws_tls) {
+ if (vd->tlscreds) {
vs->ioc_tag = qio_channel_add_watch(
vs->ioc, G_IO_IN, vncws_tls_handshake_io, vs, NULL);
} else {
@@ -3041,26 +3046,6 @@ static void vnc_connect(VncDisplay *vd, QIOChannelSocket *sioc,
vnc_qmp_event(vs, QAPI_EVENT_VNC_CONNECTED);
vnc_set_share_mode(vs, VNC_SHARE_MODE_CONNECTING);
- if (!vs->websocket) {
- vnc_init_state(vs);
- }
-
- if (vd->num_connecting > vd->connections_limit) {
- QTAILQ_FOREACH(vs, &vd->clients, next) {
- if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
- vnc_disconnect_start(vs);
- return;
- }
- }
- }
-}
-
-void vnc_init_state(VncState *vs)
-{
- vs->initialized = true;
- VncDisplay *vd = vs->vd;
- bool first_client = QTAILQ_EMPTY(&vd->clients);
-
vs->last_x = -1;
vs->last_y = -1;
@@ -3079,34 +3064,48 @@ void vnc_init_state(VncState *vs)
graphic_hw_update(vd->dcl.con);
+ if (!vs->websocket) {
+ vnc_start_protocol(vs);
+ }
+
+ if (vd->num_connecting > vd->connections_limit) {
+ QTAILQ_FOREACH(vs, &vd->clients, next) {
+ if (vs->share_mode == VNC_SHARE_MODE_CONNECTING) {
+ vnc_disconnect_start(vs);
+ return;
+ }
+ }
+ }
+}
+
+void vnc_start_protocol(VncState *vs)
+{
vnc_write(vs, "RFB 003.008\n", 12);
vnc_flush(vs);
vnc_read_when(vs, protocol_version, 12);
- reset_keys(vs);
if (vs->vd->lock_key_sync)
vs->led = qemu_add_led_event_handler(kbd_leds, vs);
vs->mouse_mode_notifier.notify = check_pointer_type_change;
qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier);
-
- /* vs might be free()ed here */
}
static gboolean vnc_listen_io(QIOChannel *ioc,
GIOCondition condition,
void *opaque)
{
- VncDisplay *vs = opaque;
+ VncDisplay *vd = opaque;
QIOChannelSocket *sioc = NULL;
Error *err = NULL;
- /* Catch-up */
- graphic_hw_update(vs->dcl.con);
sioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc), &err);
if (sioc != NULL) {
+ qio_channel_set_name(QIO_CHANNEL(sioc),
+ ioc != QIO_CHANNEL(vd->lsock) ?
+ "vnc-ws-server" : "vnc-server");
qio_channel_set_delay(QIO_CHANNEL(sioc), false);
- vnc_connect(vs, sioc, false,
- ioc != QIO_CHANNEL(vs->lsock));
+ vnc_connect(vd, sioc, false,
+ ioc != QIO_CHANNEL(vd->lsock));
object_unref(OBJECT(sioc));
} else {
/* client probably closed connection before we got there */
@@ -3129,108 +3128,108 @@ static const DisplayChangeListenerOps dcl_ops = {
void vnc_display_init(const char *id)
{
- VncDisplay *vs;
+ VncDisplay *vd;
if (vnc_display_find(id) != NULL) {
return;
}
- vs = g_malloc0(sizeof(*vs));
+ vd = g_malloc0(sizeof(*vd));
- vs->id = strdup(id);
- QTAILQ_INSERT_TAIL(&vnc_displays, vs, next);
+ vd->id = strdup(id);
+ QTAILQ_INSERT_TAIL(&vnc_displays, vd, next);
- QTAILQ_INIT(&vs->clients);
- vs->expires = TIME_MAX;
+ QTAILQ_INIT(&vd->clients);
+ vd->expires = TIME_MAX;
if (keyboard_layout) {
trace_vnc_key_map_init(keyboard_layout);
- vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
+ vd->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
} else {
- vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
+ vd->kbd_layout = init_keyboard_layout(name2keysym, "en-us");
}
- if (!vs->kbd_layout)
+ if (!vd->kbd_layout) {
exit(1);
+ }
- vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
- vs->connections_limit = 32;
+ vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+ vd->connections_limit = 32;
- qemu_mutex_init(&vs->mutex);
+ qemu_mutex_init(&vd->mutex);
vnc_start_worker_thread();
- vs->dcl.ops = &dcl_ops;
- register_displaychangelistener(&vs->dcl);
+ vd->dcl.ops = &dcl_ops;
+ register_displaychangelistener(&vd->dcl);
}
-static void vnc_display_close(VncDisplay *vs)
+static void vnc_display_close(VncDisplay *vd)
{
- if (!vs)
+ if (!vd) {
return;
- vs->enabled = false;
- vs->is_unix = false;
- if (vs->lsock != NULL) {
- if (vs->lsock_tag) {
- g_source_remove(vs->lsock_tag);
+ }
+ vd->is_unix = false;
+ if (vd->lsock != NULL) {
+ if (vd->lsock_tag) {
+ g_source_remove(vd->lsock_tag);
}
- object_unref(OBJECT(vs->lsock));
- vs->lsock = NULL;
+ object_unref(OBJECT(vd->lsock));
+ vd->lsock = NULL;
}
- vs->ws_enabled = false;
- if (vs->lwebsock != NULL) {
- if (vs->lwebsock_tag) {
- g_source_remove(vs->lwebsock_tag);
+ if (vd->lwebsock != NULL) {
+ if (vd->lwebsock_tag) {
+ g_source_remove(vd->lwebsock_tag);
}
- object_unref(OBJECT(vs->lwebsock));
- vs->lwebsock = NULL;
+ object_unref(OBJECT(vd->lwebsock));
+ vd->lwebsock = NULL;
}
- vs->auth = VNC_AUTH_INVALID;
- vs->subauth = VNC_AUTH_INVALID;
- if (vs->tlscreds) {
- object_unparent(OBJECT(vs->tlscreds));
- vs->tlscreds = NULL;
+ vd->auth = VNC_AUTH_INVALID;
+ vd->subauth = VNC_AUTH_INVALID;
+ if (vd->tlscreds) {
+ object_unparent(OBJECT(vd->tlscreds));
+ vd->tlscreds = NULL;
}
- g_free(vs->tlsaclname);
- vs->tlsaclname = NULL;
+ g_free(vd->tlsaclname);
+ vd->tlsaclname = NULL;
}
int vnc_display_password(const char *id, const char *password)
{
- VncDisplay *vs = vnc_display_find(id);
+ VncDisplay *vd = vnc_display_find(id);
- if (!vs) {
+ if (!vd) {
return -EINVAL;
}
- if (vs->auth == VNC_AUTH_NONE) {
+ if (vd->auth == VNC_AUTH_NONE) {
error_printf_unless_qmp("If you want use passwords please enable "
"password auth using '-vnc ${dpy},password'.\n");
return -EINVAL;
}
- g_free(vs->password);
- vs->password = g_strdup(password);
+ g_free(vd->password);
+ vd->password = g_strdup(password);
return 0;
}
int vnc_display_pw_expire(const char *id, time_t expires)
{
- VncDisplay *vs = vnc_display_find(id);
+ VncDisplay *vd = vnc_display_find(id);
- if (!vs) {
+ if (!vd) {
return -EINVAL;
}
- vs->expires = expires;
+ vd->expires = expires;
return 0;
}
-static void vnc_display_print_local_addr(VncDisplay *vs)
+static void vnc_display_print_local_addr(VncDisplay *vd)
{
SocketAddress *addr;
Error *err = NULL;
- addr = qio_channel_socket_get_local_address(vs->lsock, &err);
+ addr = qio_channel_socket_get_local_address(vd->lsock, &err);
if (!addr) {
return;
}
@@ -3323,7 +3322,9 @@ static QemuOptsList qemu_vnc_opts = {
static int
-vnc_display_setup_auth(VncDisplay *vs,
+vnc_display_setup_auth(int *auth,
+ int *subauth,
+ QCryptoTLSCreds *tlscreds,
bool password,
bool sasl,
bool websocket,
@@ -3376,95 +3377,56 @@ vnc_display_setup_auth(VncDisplay *vs,
* VNC auth mechs for plain VNC vs websockets VNC, the end
* result has the same security characteristics.
*/
- if (password) {
- if (vs->tlscreds) {
- vs->auth = VNC_AUTH_VENCRYPT;
- if (websocket) {
- vs->ws_tls = true;
- }
- if (object_dynamic_cast(OBJECT(vs->tlscreds),
- TYPE_QCRYPTO_TLS_CREDS_X509)) {
- VNC_DEBUG("Initializing VNC server with x509 password auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_X509VNC;
- } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
- TYPE_QCRYPTO_TLS_CREDS_ANON)) {
- VNC_DEBUG("Initializing VNC server with TLS password auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC;
- } else {
- error_setg(errp,
- "Unsupported TLS cred type %s",
- object_get_typename(OBJECT(vs->tlscreds)));
- return -1;
- }
- } else {
+ if (websocket || !tlscreds) {
+ if (password) {
VNC_DEBUG("Initializing VNC server with password auth\n");
- vs->auth = VNC_AUTH_VNC;
- vs->subauth = VNC_AUTH_INVALID;
- }
- if (websocket) {
- vs->ws_auth = VNC_AUTH_VNC;
+ *auth = VNC_AUTH_VNC;
+ } else if (sasl) {
+ VNC_DEBUG("Initializing VNC server with SASL auth\n");
+ *auth = VNC_AUTH_SASL;
} else {
- vs->ws_auth = VNC_AUTH_INVALID;
+ VNC_DEBUG("Initializing VNC server with no auth\n");
+ *auth = VNC_AUTH_NONE;
}
- } else if (sasl) {
- if (vs->tlscreds) {
- vs->auth = VNC_AUTH_VENCRYPT;
- if (websocket) {
- vs->ws_tls = true;
+ *subauth = VNC_AUTH_INVALID;
+ } else {
+ bool is_x509 = object_dynamic_cast(OBJECT(tlscreds),
+ TYPE_QCRYPTO_TLS_CREDS_X509) != NULL;
+ bool is_anon = object_dynamic_cast(OBJECT(tlscreds),
+ TYPE_QCRYPTO_TLS_CREDS_ANON) != NULL;
+
+ if (!is_x509 && !is_anon) {
+ error_setg(errp,
+ "Unsupported TLS cred type %s",
+ object_get_typename(OBJECT(tlscreds)));
+ return -1;
+ }
+ *auth = VNC_AUTH_VENCRYPT;
+ if (password) {
+ if (is_x509) {
+ VNC_DEBUG("Initializing VNC server with x509 password auth\n");
+ *subauth = VNC_AUTH_VENCRYPT_X509VNC;
+ } else {
+ VNC_DEBUG("Initializing VNC server with TLS password auth\n");
+ *subauth = VNC_AUTH_VENCRYPT_TLSVNC;
}
- if (object_dynamic_cast(OBJECT(vs->tlscreds),
- TYPE_QCRYPTO_TLS_CREDS_X509)) {
+
+ } else if (sasl) {
+ if (is_x509) {
VNC_DEBUG("Initializing VNC server with x509 SASL auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_X509SASL;
- } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
- TYPE_QCRYPTO_TLS_CREDS_ANON)) {
- VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL;
+ *subauth = VNC_AUTH_VENCRYPT_X509SASL;
} else {
- error_setg(errp,
- "Unsupported TLS cred type %s",
- object_get_typename(OBJECT(vs->tlscreds)));
- return -1;
+ VNC_DEBUG("Initializing VNC server with TLS SASL auth\n");
+ *subauth = VNC_AUTH_VENCRYPT_TLSSASL;
}
} else {
- VNC_DEBUG("Initializing VNC server with SASL auth\n");
- vs->auth = VNC_AUTH_SASL;
- vs->subauth = VNC_AUTH_INVALID;
- }
- if (websocket) {
- vs->ws_auth = VNC_AUTH_SASL;
- } else {
- vs->ws_auth = VNC_AUTH_INVALID;
- }
- } else {
- if (vs->tlscreds) {
- vs->auth = VNC_AUTH_VENCRYPT;
- if (websocket) {
- vs->ws_tls = true;
- }
- if (object_dynamic_cast(OBJECT(vs->tlscreds),
- TYPE_QCRYPTO_TLS_CREDS_X509)) {
+ if (is_x509) {
VNC_DEBUG("Initializing VNC server with x509 no auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_X509NONE;
- } else if (object_dynamic_cast(OBJECT(vs->tlscreds),
- TYPE_QCRYPTO_TLS_CREDS_ANON)) {
- VNC_DEBUG("Initializing VNC server with TLS no auth\n");
- vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE;
+ *subauth = VNC_AUTH_VENCRYPT_X509NONE;
} else {
- error_setg(errp,
- "Unsupported TLS cred type %s",
- object_get_typename(OBJECT(vs->tlscreds)));
- return -1;
+ VNC_DEBUG("Initializing VNC server with TLS no auth\n");
+ *subauth = VNC_AUTH_VENCRYPT_TLSNONE;
}
- } else {
- VNC_DEBUG("Initializing VNC server with no auth\n");
- vs->auth = VNC_AUTH_NONE;
- vs->subauth = VNC_AUTH_INVALID;
- }
- if (websocket) {
- vs->ws_auth = VNC_AUTH_NONE;
- } else {
- vs->ws_auth = VNC_AUTH_INVALID;
}
}
return 0;
@@ -3518,7 +3480,7 @@ vnc_display_create_creds(bool x509,
void vnc_display_open(const char *id, Error **errp)
{
- VncDisplay *vs = vnc_display_find(id);
+ VncDisplay *vd = vnc_display_find(id);
QemuOpts *opts = qemu_opts_find(&qemu_vnc_opts, id);
SocketAddress *saddr = NULL, *wsaddr = NULL;
const char *share, *device_id;
@@ -3536,12 +3498,13 @@ void vnc_display_open(const char *id, Error **errp)
int acl = 0;
int lock_key_sync = 1;
int key_delay_ms;
+ bool ws_enabled = false;
- if (!vs) {
+ if (!vd) {
error_setg(errp, "VNC display not active");
return;
}
- vnc_display_close(vs);
+ vnc_display_close(vd);
if (!opts) {
return;
@@ -3571,7 +3534,7 @@ void vnc_display_open(const char *id, Error **errp)
}
wsaddr = g_new0(SocketAddress, 1);
- vs->ws_enabled = true;
+ ws_enabled = true;
}
if (strncmp(vnc, "unix:", 5) == 0) {
@@ -3579,7 +3542,7 @@ void vnc_display_open(const char *id, Error **errp)
saddr->u.q_unix.data = g_new0(UnixSocketAddress, 1);
saddr->u.q_unix.data->path = g_strdup(vnc + 5);
- if (vs->ws_enabled) {
+ if (ws_enabled) {
error_setg(errp, "UNIX sockets not supported with websock");
goto fail;
}
@@ -3615,7 +3578,7 @@ void vnc_display_open(const char *id, Error **errp)
inet->ipv6 = ipv6;
inet->has_ipv6 = has_ipv6;
- if (vs->ws_enabled) {
+ if (ws_enabled) {
wsaddr->type = SOCKET_ADDRESS_KIND_INET;
inet = wsaddr->u.inet.data = g_new0(InetSocketAddress, 1);
inet->host = g_strdup(saddr->u.inet.data->host);
@@ -3646,7 +3609,7 @@ void vnc_display_open(const char *id, Error **errp)
goto fail;
}
if (!qcrypto_cipher_supports(
- QCRYPTO_CIPHER_ALG_DES_RFB)) {
+ QCRYPTO_CIPHER_ALG_DES_RFB, QCRYPTO_CIPHER_MODE_ECB)) {
error_setg(errp,
"Cipher backend does not support DES RFB algorithm");
goto fail;
@@ -3682,17 +3645,17 @@ void vnc_display_open(const char *id, Error **errp)
credid);
goto fail;
}
- vs->tlscreds = (QCryptoTLSCreds *)
+ vd->tlscreds = (QCryptoTLSCreds *)
object_dynamic_cast(creds,
TYPE_QCRYPTO_TLS_CREDS);
- if (!vs->tlscreds) {
+ if (!vd->tlscreds) {
error_setg(errp, "Object with id '%s' is not TLS credentials",
credid);
goto fail;
}
- object_ref(OBJECT(vs->tlscreds));
+ object_ref(OBJECT(vd->tlscreds));
- if (vs->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
+ if (vd->tlscreds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
error_setg(errp,
"Expecting TLS credentials with a server endpoint");
goto fail;
@@ -3713,12 +3676,12 @@ void vnc_display_open(const char *id, Error **errp)
x509verify = true;
}
}
- vs->tlscreds = vnc_display_create_creds(x509,
+ vd->tlscreds = vnc_display_create_creds(x509,
x509verify,
path,
- vs->id,
+ vd->id,
errp);
- if (!vs->tlscreds) {
+ if (!vd->tlscreds) {
goto fail;
}
}
@@ -3728,54 +3691,62 @@ void vnc_display_open(const char *id, Error **errp)
share = qemu_opt_get(opts, "share");
if (share) {
if (strcmp(share, "ignore") == 0) {
- vs->share_policy = VNC_SHARE_POLICY_IGNORE;
+ vd->share_policy = VNC_SHARE_POLICY_IGNORE;
} else if (strcmp(share, "allow-exclusive") == 0) {
- vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+ vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
} else if (strcmp(share, "force-shared") == 0) {
- vs->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
+ vd->share_policy = VNC_SHARE_POLICY_FORCE_SHARED;
} else {
error_setg(errp, "unknown vnc share= option");
goto fail;
}
} else {
- vs->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
+ vd->share_policy = VNC_SHARE_POLICY_ALLOW_EXCLUSIVE;
}
- vs->connections_limit = qemu_opt_get_number(opts, "connections", 32);
+ vd->connections_limit = qemu_opt_get_number(opts, "connections", 32);
#ifdef CONFIG_VNC_JPEG
- vs->lossy = qemu_opt_get_bool(opts, "lossy", false);
+ vd->lossy = qemu_opt_get_bool(opts, "lossy", false);
#endif
- vs->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
+ vd->non_adaptive = qemu_opt_get_bool(opts, "non-adaptive", false);
/* adaptive updates are only used with tight encoding and
* if lossy updates are enabled so we can disable all the
* calculations otherwise */
- if (!vs->lossy) {
- vs->non_adaptive = true;
+ if (!vd->lossy) {
+ vd->non_adaptive = true;
}
if (acl) {
- if (strcmp(vs->id, "default") == 0) {
- vs->tlsaclname = g_strdup("vnc.x509dname");
+ if (strcmp(vd->id, "default") == 0) {
+ vd->tlsaclname = g_strdup("vnc.x509dname");
} else {
- vs->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vs->id);
+ vd->tlsaclname = g_strdup_printf("vnc.%s.x509dname", vd->id);
}
- qemu_acl_init(vs->tlsaclname);
+ qemu_acl_init(vd->tlsaclname);
}
#ifdef CONFIG_VNC_SASL
if (acl && sasl) {
char *aclname;
- if (strcmp(vs->id, "default") == 0) {
+ if (strcmp(vd->id, "default") == 0) {
aclname = g_strdup("vnc.username");
} else {
- aclname = g_strdup_printf("vnc.%s.username", vs->id);
+ aclname = g_strdup_printf("vnc.%s.username", vd->id);
}
- vs->sasl.acl = qemu_acl_init(aclname);
+ vd->sasl.acl = qemu_acl_init(aclname);
g_free(aclname);
}
#endif
- if (vnc_display_setup_auth(vs, password, sasl, vs->ws_enabled, errp) < 0) {
+ if (vnc_display_setup_auth(&vd->auth, &vd->subauth,
+ vd->tlscreds, password,
+ sasl, false, errp) < 0) {
+ goto fail;
+ }
+
+ if (vnc_display_setup_auth(&vd->ws_auth, &vd->ws_subauth,
+ vd->tlscreds, password,
+ sasl, true, errp) < 0) {
goto fail;
}
@@ -3786,8 +3757,8 @@ void vnc_display_open(const char *id, Error **errp)
goto fail;
}
#endif
- vs->lock_key_sync = lock_key_sync;
- vs->key_delay_ms = key_delay_ms;
+ vd->lock_key_sync = lock_key_sync;
+ vd->key_delay_ms = key_delay_ms;
device_id = qemu_opt_get(opts, "display");
if (device_id) {
@@ -3803,58 +3774,60 @@ void vnc_display_open(const char *id, Error **errp)
con = NULL;
}
- if (con != vs->dcl.con) {
- unregister_displaychangelistener(&vs->dcl);
- vs->dcl.con = con;
- register_displaychangelistener(&vs->dcl);
+ if (con != vd->dcl.con) {
+ unregister_displaychangelistener(&vd->dcl);
+ vd->dcl.con = con;
+ register_displaychangelistener(&vd->dcl);
}
if (reverse) {
/* connect to viewer */
QIOChannelSocket *sioc = NULL;
- vs->lsock = NULL;
- vs->lwebsock = NULL;
- if (vs->ws_enabled) {
+ vd->lsock = NULL;
+ vd->lwebsock = NULL;
+ if (ws_enabled) {
error_setg(errp, "Cannot use websockets in reverse mode");
goto fail;
}
- vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
+ vd->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
sioc = qio_channel_socket_new();
+ qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-reverse");
if (qio_channel_socket_connect_sync(sioc, saddr, errp) < 0) {
goto fail;
}
- vnc_connect(vs, sioc, false, false);
+ vnc_connect(vd, sioc, false, false);
object_unref(OBJECT(sioc));
} else {
- vs->lsock = qio_channel_socket_new();
- if (qio_channel_socket_listen_sync(vs->lsock, saddr, errp) < 0) {
+ vd->lsock = qio_channel_socket_new();
+ qio_channel_set_name(QIO_CHANNEL(vd->lsock), "vnc-listen");
+ if (qio_channel_socket_listen_sync(vd->lsock, saddr, errp) < 0) {
goto fail;
}
- vs->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
- vs->enabled = true;
+ vd->is_unix = saddr->type == SOCKET_ADDRESS_KIND_UNIX;
- if (vs->ws_enabled) {
- vs->lwebsock = qio_channel_socket_new();
- if (qio_channel_socket_listen_sync(vs->lwebsock,
+ if (ws_enabled) {
+ vd->lwebsock = qio_channel_socket_new();
+ qio_channel_set_name(QIO_CHANNEL(vd->lwebsock), "vnc-ws-listen");
+ if (qio_channel_socket_listen_sync(vd->lwebsock,
wsaddr, errp) < 0) {
- object_unref(OBJECT(vs->lsock));
- vs->lsock = NULL;
+ object_unref(OBJECT(vd->lsock));
+ vd->lsock = NULL;
goto fail;
}
}
- vs->lsock_tag = qio_channel_add_watch(
- QIO_CHANNEL(vs->lsock),
- G_IO_IN, vnc_listen_io, vs, NULL);
- if (vs->ws_enabled) {
- vs->lwebsock_tag = qio_channel_add_watch(
- QIO_CHANNEL(vs->lwebsock),
- G_IO_IN, vnc_listen_io, vs, NULL);
+ vd->lsock_tag = qio_channel_add_watch(
+ QIO_CHANNEL(vd->lsock),
+ G_IO_IN, vnc_listen_io, vd, NULL);
+ if (ws_enabled) {
+ vd->lwebsock_tag = qio_channel_add_watch(
+ QIO_CHANNEL(vd->lwebsock),
+ G_IO_IN, vnc_listen_io, vd, NULL);
}
}
if (show_vnc_port) {
- vnc_display_print_local_addr(vs);
+ vnc_display_print_local_addr(vd);
}
qapi_free_SocketAddress(saddr);
@@ -3864,22 +3837,22 @@ void vnc_display_open(const char *id, Error **errp)
fail:
qapi_free_SocketAddress(saddr);
qapi_free_SocketAddress(wsaddr);
- vs->enabled = false;
- vs->ws_enabled = false;
+ ws_enabled = false;
}
void vnc_display_add_client(const char *id, int csock, bool skipauth)
{
- VncDisplay *vs = vnc_display_find(id);
+ VncDisplay *vd = vnc_display_find(id);
QIOChannelSocket *sioc;
- if (!vs) {
+ if (!vd) {
return;
}
sioc = qio_channel_socket_new_fd(csock, NULL);
if (sioc) {
- vnc_connect(vs, sioc, skipauth, false);
+ qio_channel_set_name(QIO_CHANNEL(sioc), "vnc-server");
+ vnc_connect(vd, sioc, skipauth, false);
object_unref(OBJECT(sioc));
}
}
diff --git a/ui/vnc.h b/ui/vnc.h
index ab5f244116..d20b154a77 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -150,7 +150,6 @@ struct VncDisplay
guint lsock_tag;
QIOChannelSocket *lwebsock;
guint lwebsock_tag;
- bool ws_enabled;
DisplaySurface *ds;
DisplayChangeListener dcl;
kbd_layout_t *kbd_layout;
@@ -167,14 +166,13 @@ struct VncDisplay
const char *id;
QTAILQ_ENTRY(VncDisplay) next;
- bool enabled;
bool is_unix;
char *password;
time_t expires;
int auth;
int subauth; /* Used by VeNCrypt */
int ws_auth; /* Used by websockets */
- bool ws_tls; /* Used by websockets */
+ int ws_subauth; /* Used by websockets */
bool lossy;
bool non_adaptive;
QCryptoTLSCreds *tlscreds;
@@ -309,7 +307,6 @@ struct VncState
QEMUPutLEDEntry *led;
bool abort;
- bool initialized;
QemuMutex output_mutex;
QEMUBH *bh;
Buffer jobs_buffer;
@@ -518,7 +515,7 @@ void vnc_write_u8(VncState *vs, uint8_t value);
void vnc_flush(VncState *vs);
void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting);
void vnc_disconnect_finish(VncState *vs);
-void vnc_init_state(VncState *vs);
+void vnc_start_protocol(VncState *vs);
/* Buffer I/O functions */