diff options
author | SeokYeon Hwang <syeon.hwang@samsung.com> | 2016-12-20 10:13:15 +0900 |
---|---|---|
committer | SeokYeon Hwang <syeon.hwang@samsung.com> | 2016-12-20 10:13:15 +0900 |
commit | dc36664b156b6aa2b55f2bca5fd0c643b6417ddb (patch) | |
tree | bb319daf3cd759c2d91dd541bb2ee24d8ca4ee1a /ui | |
parent | 100d9fdc18f28d813f9d22025d783a7cdcc4bb4b (diff) | |
parent | 6a928d25b6d8bc3729c3d28326c6db13b9481059 (diff) | |
download | qemu-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.m | 123 | ||||
-rw-r--r-- | ui/console.c | 40 | ||||
-rw-r--r-- | ui/curses.c | 24 | ||||
-rw-r--r-- | ui/gtk.c | 44 | ||||
-rw-r--r-- | ui/input-linux.c | 15 | ||||
-rw-r--r-- | ui/spice-core.c | 2 | ||||
-rw-r--r-- | ui/spice-display.c | 92 | ||||
-rw-r--r-- | ui/vnc-auth-vencrypt.c | 1 | ||||
-rw-r--r-- | ui/vnc-enc-tight.c | 6 | ||||
-rw-r--r-- | ui/vnc-ws.c | 5 | ||||
-rw-r--r-- | ui/vnc.c | 423 | ||||
-rw-r--r-- | ui/vnc.h | 7 |
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; @@ -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); @@ -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)); } } @@ -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 */ |