|
|
1.1 ! root 1: /* ! 2: * QEMU VNC display driver ! 3: * ! 4: * Copyright (C) 2006 Anthony Liguori <[email protected]> ! 5: * Copyright (C) 2006 Fabrice Bellard ! 6: * Copyright (C) 2009 Red Hat, Inc ! 7: * ! 8: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 9: * of this software and associated documentation files (the "Software"), to deal ! 10: * in the Software without restriction, including without limitation the rights ! 11: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 12: * copies of the Software, and to permit persons to whom the Software is ! 13: * furnished to do so, subject to the following conditions: ! 14: * ! 15: * The above copyright notice and this permission notice shall be included in ! 16: * all copies or substantial portions of the Software. ! 17: * ! 18: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 19: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 20: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 21: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 22: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 23: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 24: * THE SOFTWARE. ! 25: */ ! 26: ! 27: #include "vnc.h" ! 28: #include "vnc-jobs.h" ! 29: #include "sysemu.h" ! 30: #include "qemu_socket.h" ! 31: #include "qemu-timer.h" ! 32: #include "acl.h" ! 33: #include "qemu-objects.h" ! 34: ! 35: #define VNC_REFRESH_INTERVAL_BASE 30 ! 36: #define VNC_REFRESH_INTERVAL_INC 50 ! 37: #define VNC_REFRESH_INTERVAL_MAX 2000 ! 38: ! 39: #include "vnc_keysym.h" ! 40: #include "d3des.h" ! 41: ! 42: #define count_bits(c, v) { \ ! 43: for (c = 0; v; v >>= 1) \ ! 44: { \ ! 45: c += v & 1; \ ! 46: } \ ! 47: } ! 48: ! 49: static VncDisplay *vnc_display; /* needed for info vnc */ ! 50: static DisplayChangeListener *dcl; ! 51: ! 52: static int vnc_cursor_define(VncState *vs); ! 53: ! 54: static char *addr_to_string(const char *format, ! 55: struct sockaddr_storage *sa, ! 56: socklen_t salen) { ! 57: char *addr; ! 58: char host[NI_MAXHOST]; ! 59: char serv[NI_MAXSERV]; ! 60: int err; ! 61: size_t addrlen; ! 62: ! 63: if ((err = getnameinfo((struct sockaddr *)sa, salen, ! 64: host, sizeof(host), ! 65: serv, sizeof(serv), ! 66: NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { ! 67: VNC_DEBUG("Cannot resolve address %d: %s\n", ! 68: err, gai_strerror(err)); ! 69: return NULL; ! 70: } ! 71: ! 72: /* Enough for the existing format + the 2 vars we're ! 73: * substituting in. */ ! 74: addrlen = strlen(format) + strlen(host) + strlen(serv); ! 75: addr = qemu_malloc(addrlen + 1); ! 76: snprintf(addr, addrlen, format, host, serv); ! 77: addr[addrlen] = '\0'; ! 78: ! 79: return addr; ! 80: } ! 81: ! 82: ! 83: char *vnc_socket_local_addr(const char *format, int fd) { ! 84: struct sockaddr_storage sa; ! 85: socklen_t salen; ! 86: ! 87: salen = sizeof(sa); ! 88: if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) ! 89: return NULL; ! 90: ! 91: return addr_to_string(format, &sa, salen); ! 92: } ! 93: ! 94: char *vnc_socket_remote_addr(const char *format, int fd) { ! 95: struct sockaddr_storage sa; ! 96: socklen_t salen; ! 97: ! 98: salen = sizeof(sa); ! 99: if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) ! 100: return NULL; ! 101: ! 102: return addr_to_string(format, &sa, salen); ! 103: } ! 104: ! 105: static int put_addr_qdict(QDict *qdict, struct sockaddr_storage *sa, ! 106: socklen_t salen) ! 107: { ! 108: char host[NI_MAXHOST]; ! 109: char serv[NI_MAXSERV]; ! 110: int err; ! 111: ! 112: if ((err = getnameinfo((struct sockaddr *)sa, salen, ! 113: host, sizeof(host), ! 114: serv, sizeof(serv), ! 115: NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { ! 116: VNC_DEBUG("Cannot resolve address %d: %s\n", ! 117: err, gai_strerror(err)); ! 118: return -1; ! 119: } ! 120: ! 121: qdict_put(qdict, "host", qstring_from_str(host)); ! 122: qdict_put(qdict, "service", qstring_from_str(serv)); ! 123: qdict_put(qdict, "family",qstring_from_str(inet_strfamily(sa->ss_family))); ! 124: ! 125: return 0; ! 126: } ! 127: ! 128: static int vnc_server_addr_put(QDict *qdict, int fd) ! 129: { ! 130: struct sockaddr_storage sa; ! 131: socklen_t salen; ! 132: ! 133: salen = sizeof(sa); ! 134: if (getsockname(fd, (struct sockaddr*)&sa, &salen) < 0) { ! 135: return -1; ! 136: } ! 137: ! 138: return put_addr_qdict(qdict, &sa, salen); ! 139: } ! 140: ! 141: static int vnc_qdict_remote_addr(QDict *qdict, int fd) ! 142: { ! 143: struct sockaddr_storage sa; ! 144: socklen_t salen; ! 145: ! 146: salen = sizeof(sa); ! 147: if (getpeername(fd, (struct sockaddr*)&sa, &salen) < 0) { ! 148: return -1; ! 149: } ! 150: ! 151: return put_addr_qdict(qdict, &sa, salen); ! 152: } ! 153: ! 154: static const char *vnc_auth_name(VncDisplay *vd) { ! 155: switch (vd->auth) { ! 156: case VNC_AUTH_INVALID: ! 157: return "invalid"; ! 158: case VNC_AUTH_NONE: ! 159: return "none"; ! 160: case VNC_AUTH_VNC: ! 161: return "vnc"; ! 162: case VNC_AUTH_RA2: ! 163: return "ra2"; ! 164: case VNC_AUTH_RA2NE: ! 165: return "ra2ne"; ! 166: case VNC_AUTH_TIGHT: ! 167: return "tight"; ! 168: case VNC_AUTH_ULTRA: ! 169: return "ultra"; ! 170: case VNC_AUTH_TLS: ! 171: return "tls"; ! 172: case VNC_AUTH_VENCRYPT: ! 173: #ifdef CONFIG_VNC_TLS ! 174: switch (vd->subauth) { ! 175: case VNC_AUTH_VENCRYPT_PLAIN: ! 176: return "vencrypt+plain"; ! 177: case VNC_AUTH_VENCRYPT_TLSNONE: ! 178: return "vencrypt+tls+none"; ! 179: case VNC_AUTH_VENCRYPT_TLSVNC: ! 180: return "vencrypt+tls+vnc"; ! 181: case VNC_AUTH_VENCRYPT_TLSPLAIN: ! 182: return "vencrypt+tls+plain"; ! 183: case VNC_AUTH_VENCRYPT_X509NONE: ! 184: return "vencrypt+x509+none"; ! 185: case VNC_AUTH_VENCRYPT_X509VNC: ! 186: return "vencrypt+x509+vnc"; ! 187: case VNC_AUTH_VENCRYPT_X509PLAIN: ! 188: return "vencrypt+x509+plain"; ! 189: case VNC_AUTH_VENCRYPT_TLSSASL: ! 190: return "vencrypt+tls+sasl"; ! 191: case VNC_AUTH_VENCRYPT_X509SASL: ! 192: return "vencrypt+x509+sasl"; ! 193: default: ! 194: return "vencrypt"; ! 195: } ! 196: #else ! 197: return "vencrypt"; ! 198: #endif ! 199: case VNC_AUTH_SASL: ! 200: return "sasl"; ! 201: } ! 202: return "unknown"; ! 203: } ! 204: ! 205: static int vnc_server_info_put(QDict *qdict) ! 206: { ! 207: if (vnc_server_addr_put(qdict, vnc_display->lsock) < 0) { ! 208: return -1; ! 209: } ! 210: ! 211: qdict_put(qdict, "auth", qstring_from_str(vnc_auth_name(vnc_display))); ! 212: return 0; ! 213: } ! 214: ! 215: static void vnc_client_cache_auth(VncState *client) ! 216: { ! 217: QDict *qdict; ! 218: ! 219: if (!client->info) { ! 220: return; ! 221: } ! 222: ! 223: qdict = qobject_to_qdict(client->info); ! 224: ! 225: #ifdef CONFIG_VNC_TLS ! 226: if (client->tls.session && ! 227: client->tls.dname) { ! 228: qdict_put(qdict, "x509_dname", qstring_from_str(client->tls.dname)); ! 229: } ! 230: #endif ! 231: #ifdef CONFIG_VNC_SASL ! 232: if (client->sasl.conn && ! 233: client->sasl.username) { ! 234: qdict_put(qdict, "sasl_username", ! 235: qstring_from_str(client->sasl.username)); ! 236: } ! 237: #endif ! 238: } ! 239: ! 240: static void vnc_client_cache_addr(VncState *client) ! 241: { ! 242: QDict *qdict; ! 243: ! 244: qdict = qdict_new(); ! 245: if (vnc_qdict_remote_addr(qdict, client->csock) < 0) { ! 246: QDECREF(qdict); ! 247: /* XXX: how to report the error? */ ! 248: return; ! 249: } ! 250: ! 251: client->info = QOBJECT(qdict); ! 252: } ! 253: ! 254: static void vnc_qmp_event(VncState *vs, MonitorEvent event) ! 255: { ! 256: QDict *server; ! 257: QObject *data; ! 258: ! 259: if (!vs->info) { ! 260: return; ! 261: } ! 262: ! 263: server = qdict_new(); ! 264: if (vnc_server_info_put(server) < 0) { ! 265: QDECREF(server); ! 266: return; ! 267: } ! 268: ! 269: data = qobject_from_jsonf("{ 'client': %p, 'server': %p }", ! 270: vs->info, QOBJECT(server)); ! 271: ! 272: monitor_protocol_event(event, data); ! 273: ! 274: qobject_incref(vs->info); ! 275: qobject_decref(data); ! 276: } ! 277: ! 278: static void info_vnc_iter(QObject *obj, void *opaque) ! 279: { ! 280: QDict *client; ! 281: Monitor *mon = opaque; ! 282: ! 283: client = qobject_to_qdict(obj); ! 284: monitor_printf(mon, "Client:\n"); ! 285: monitor_printf(mon, " address: %s:%s\n", ! 286: qdict_get_str(client, "host"), ! 287: qdict_get_str(client, "service")); ! 288: ! 289: #ifdef CONFIG_VNC_TLS ! 290: monitor_printf(mon, " x509_dname: %s\n", ! 291: qdict_haskey(client, "x509_dname") ? ! 292: qdict_get_str(client, "x509_dname") : "none"); ! 293: #endif ! 294: #ifdef CONFIG_VNC_SASL ! 295: monitor_printf(mon, " username: %s\n", ! 296: qdict_haskey(client, "sasl_username") ? ! 297: qdict_get_str(client, "sasl_username") : "none"); ! 298: #endif ! 299: } ! 300: ! 301: void do_info_vnc_print(Monitor *mon, const QObject *data) ! 302: { ! 303: QDict *server; ! 304: QList *clients; ! 305: ! 306: server = qobject_to_qdict(data); ! 307: if (qdict_get_bool(server, "enabled") == 0) { ! 308: monitor_printf(mon, "Server: disabled\n"); ! 309: return; ! 310: } ! 311: ! 312: monitor_printf(mon, "Server:\n"); ! 313: monitor_printf(mon, " address: %s:%s\n", ! 314: qdict_get_str(server, "host"), ! 315: qdict_get_str(server, "service")); ! 316: monitor_printf(mon, " auth: %s\n", qdict_get_str(server, "auth")); ! 317: ! 318: clients = qdict_get_qlist(server, "clients"); ! 319: if (qlist_empty(clients)) { ! 320: monitor_printf(mon, "Client: none\n"); ! 321: } else { ! 322: qlist_iter(clients, info_vnc_iter, mon); ! 323: } ! 324: } ! 325: ! 326: void do_info_vnc(Monitor *mon, QObject **ret_data) ! 327: { ! 328: if (vnc_display == NULL || vnc_display->display == NULL) { ! 329: *ret_data = qobject_from_jsonf("{ 'enabled': false }"); ! 330: } else { ! 331: QList *clist; ! 332: VncState *client; ! 333: ! 334: clist = qlist_new(); ! 335: QTAILQ_FOREACH(client, &vnc_display->clients, next) { ! 336: if (client->info) { ! 337: /* incref so that it's not freed by upper layers */ ! 338: qobject_incref(client->info); ! 339: qlist_append_obj(clist, client->info); ! 340: } ! 341: } ! 342: ! 343: *ret_data = qobject_from_jsonf("{ 'enabled': true, 'clients': %p }", ! 344: QOBJECT(clist)); ! 345: assert(*ret_data != NULL); ! 346: ! 347: if (vnc_server_info_put(qobject_to_qdict(*ret_data)) < 0) { ! 348: qobject_decref(*ret_data); ! 349: *ret_data = NULL; ! 350: } ! 351: } ! 352: } ! 353: ! 354: /* TODO ! 355: 1) Get the queue working for IO. ! 356: 2) there is some weirdness when using the -S option (the screen is grey ! 357: and not totally invalidated ! 358: 3) resolutions > 1024 ! 359: */ ! 360: ! 361: static int vnc_update_client(VncState *vs, int has_dirty); ! 362: static int vnc_update_client_sync(VncState *vs, int has_dirty); ! 363: static void vnc_disconnect_start(VncState *vs); ! 364: static void vnc_disconnect_finish(VncState *vs); ! 365: static void vnc_init_timer(VncDisplay *vd); ! 366: static void vnc_remove_timer(VncDisplay *vd); ! 367: ! 368: static void vnc_colordepth(VncState *vs); ! 369: static void framebuffer_update_request(VncState *vs, int incremental, ! 370: int x_position, int y_position, ! 371: int w, int h); ! 372: static void vnc_refresh(void *opaque); ! 373: static int vnc_refresh_server_surface(VncDisplay *vd); ! 374: ! 375: static inline void vnc_set_bit(uint32_t *d, int k) ! 376: { ! 377: d[k >> 5] |= 1 << (k & 0x1f); ! 378: } ! 379: ! 380: static inline void vnc_clear_bit(uint32_t *d, int k) ! 381: { ! 382: d[k >> 5] &= ~(1 << (k & 0x1f)); ! 383: } ! 384: ! 385: static inline void vnc_set_bits(uint32_t *d, int n, int nb_words) ! 386: { ! 387: int j; ! 388: ! 389: j = 0; ! 390: while (n >= 32) { ! 391: d[j++] = -1; ! 392: n -= 32; ! 393: } ! 394: if (n > 0) ! 395: d[j++] = (1 << n) - 1; ! 396: while (j < nb_words) ! 397: d[j++] = 0; ! 398: } ! 399: ! 400: static inline int vnc_get_bit(const uint32_t *d, int k) ! 401: { ! 402: return (d[k >> 5] >> (k & 0x1f)) & 1; ! 403: } ! 404: ! 405: static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2, ! 406: int nb_words) ! 407: { ! 408: int i; ! 409: for(i = 0; i < nb_words; i++) { ! 410: if ((d1[i] & d2[i]) != 0) ! 411: return 1; ! 412: } ! 413: return 0; ! 414: } ! 415: ! 416: static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) ! 417: { ! 418: int i; ! 419: VncDisplay *vd = ds->opaque; ! 420: struct VncSurface *s = &vd->guest; ! 421: ! 422: h += y; ! 423: ! 424: /* round x down to ensure the loop only spans one 16-pixel block per, ! 425: iteration. otherwise, if (x % 16) != 0, the last iteration may span ! 426: two 16-pixel blocks but we only mark the first as dirty ! 427: */ ! 428: w += (x % 16); ! 429: x -= (x % 16); ! 430: ! 431: x = MIN(x, s->ds->width); ! 432: y = MIN(y, s->ds->height); ! 433: w = MIN(x + w, s->ds->width) - x; ! 434: h = MIN(h, s->ds->height); ! 435: ! 436: for (; y < h; y++) ! 437: for (i = 0; i < w; i += 16) ! 438: vnc_set_bit(s->dirty[y], (x + i) / 16); ! 439: } ! 440: ! 441: void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, ! 442: int32_t encoding) ! 443: { ! 444: vnc_write_u16(vs, x); ! 445: vnc_write_u16(vs, y); ! 446: vnc_write_u16(vs, w); ! 447: vnc_write_u16(vs, h); ! 448: ! 449: vnc_write_s32(vs, encoding); ! 450: } ! 451: ! 452: void buffer_reserve(Buffer *buffer, size_t len) ! 453: { ! 454: if ((buffer->capacity - buffer->offset) < len) { ! 455: buffer->capacity += (len + 1024); ! 456: buffer->buffer = qemu_realloc(buffer->buffer, buffer->capacity); ! 457: if (buffer->buffer == NULL) { ! 458: fprintf(stderr, "vnc: out of memory\n"); ! 459: exit(1); ! 460: } ! 461: } ! 462: } ! 463: ! 464: int buffer_empty(Buffer *buffer) ! 465: { ! 466: return buffer->offset == 0; ! 467: } ! 468: ! 469: uint8_t *buffer_end(Buffer *buffer) ! 470: { ! 471: return buffer->buffer + buffer->offset; ! 472: } ! 473: ! 474: void buffer_reset(Buffer *buffer) ! 475: { ! 476: buffer->offset = 0; ! 477: } ! 478: ! 479: void buffer_free(Buffer *buffer) ! 480: { ! 481: qemu_free(buffer->buffer); ! 482: buffer->offset = 0; ! 483: buffer->capacity = 0; ! 484: buffer->buffer = NULL; ! 485: } ! 486: ! 487: void buffer_append(Buffer *buffer, const void *data, size_t len) ! 488: { ! 489: memcpy(buffer->buffer + buffer->offset, data, len); ! 490: buffer->offset += len; ! 491: } ! 492: ! 493: static void vnc_desktop_resize(VncState *vs) ! 494: { ! 495: DisplayState *ds = vs->ds; ! 496: ! 497: if (vs->csock == -1 || !vnc_has_feature(vs, VNC_FEATURE_RESIZE)) { ! 498: return; ! 499: } ! 500: if (vs->client_width == ds_get_width(ds) && ! 501: vs->client_height == ds_get_height(ds)) { ! 502: return; ! 503: } ! 504: vs->client_width = ds_get_width(ds); ! 505: vs->client_height = ds_get_height(ds); ! 506: vnc_lock_output(vs); ! 507: vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); ! 508: vnc_write_u8(vs, 0); ! 509: vnc_write_u16(vs, 1); /* number of rects */ ! 510: vnc_framebuffer_update(vs, 0, 0, vs->client_width, vs->client_height, ! 511: VNC_ENCODING_DESKTOPRESIZE); ! 512: vnc_unlock_output(vs); ! 513: vnc_flush(vs); ! 514: } ! 515: ! 516: #ifdef CONFIG_VNC_THREAD ! 517: static void vnc_abort_display_jobs(VncDisplay *vd) ! 518: { ! 519: VncState *vs; ! 520: ! 521: QTAILQ_FOREACH(vs, &vd->clients, next) { ! 522: vnc_lock_output(vs); ! 523: vs->abort = true; ! 524: vnc_unlock_output(vs); ! 525: } ! 526: QTAILQ_FOREACH(vs, &vd->clients, next) { ! 527: vnc_jobs_join(vs); ! 528: } ! 529: QTAILQ_FOREACH(vs, &vd->clients, next) { ! 530: vnc_lock_output(vs); ! 531: vs->abort = false; ! 532: vnc_unlock_output(vs); ! 533: } ! 534: } ! 535: #else ! 536: static void vnc_abort_display_jobs(VncDisplay *vd) ! 537: { ! 538: } ! 539: #endif ! 540: ! 541: static void vnc_dpy_resize(DisplayState *ds) ! 542: { ! 543: VncDisplay *vd = ds->opaque; ! 544: VncState *vs; ! 545: ! 546: vnc_abort_display_jobs(vd); ! 547: ! 548: /* server surface */ ! 549: if (!vd->server) ! 550: vd->server = qemu_mallocz(sizeof(*vd->server)); ! 551: if (vd->server->data) ! 552: qemu_free(vd->server->data); ! 553: *(vd->server) = *(ds->surface); ! 554: vd->server->data = qemu_mallocz(vd->server->linesize * ! 555: vd->server->height); ! 556: ! 557: /* guest surface */ ! 558: if (!vd->guest.ds) ! 559: vd->guest.ds = qemu_mallocz(sizeof(*vd->guest.ds)); ! 560: if (ds_get_bytes_per_pixel(ds) != vd->guest.ds->pf.bytes_per_pixel) ! 561: console_color_init(ds); ! 562: *(vd->guest.ds) = *(ds->surface); ! 563: memset(vd->guest.dirty, 0xFF, sizeof(vd->guest.dirty)); ! 564: ! 565: QTAILQ_FOREACH(vs, &vd->clients, next) { ! 566: vnc_colordepth(vs); ! 567: vnc_desktop_resize(vs); ! 568: if (vs->vd->cursor) { ! 569: vnc_cursor_define(vs); ! 570: } ! 571: memset(vs->dirty, 0xFF, sizeof(vs->dirty)); ! 572: } ! 573: } ! 574: ! 575: /* fastest code */ ! 576: static void vnc_write_pixels_copy(VncState *vs, struct PixelFormat *pf, ! 577: void *pixels, int size) ! 578: { ! 579: vnc_write(vs, pixels, size); ! 580: } ! 581: ! 582: /* slowest but generic code. */ ! 583: void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v) ! 584: { ! 585: uint8_t r, g, b; ! 586: VncDisplay *vd = vs->vd; ! 587: ! 588: r = ((((v & vd->server->pf.rmask) >> vd->server->pf.rshift) << vs->clientds.pf.rbits) >> ! 589: vd->server->pf.rbits); ! 590: g = ((((v & vd->server->pf.gmask) >> vd->server->pf.gshift) << vs->clientds.pf.gbits) >> ! 591: vd->server->pf.gbits); ! 592: b = ((((v & vd->server->pf.bmask) >> vd->server->pf.bshift) << vs->clientds.pf.bbits) >> ! 593: vd->server->pf.bbits); ! 594: v = (r << vs->clientds.pf.rshift) | ! 595: (g << vs->clientds.pf.gshift) | ! 596: (b << vs->clientds.pf.bshift); ! 597: switch(vs->clientds.pf.bytes_per_pixel) { ! 598: case 1: ! 599: buf[0] = v; ! 600: break; ! 601: case 2: ! 602: if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) { ! 603: buf[0] = v >> 8; ! 604: buf[1] = v; ! 605: } else { ! 606: buf[1] = v >> 8; ! 607: buf[0] = v; ! 608: } ! 609: break; ! 610: default: ! 611: case 4: ! 612: if (vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) { ! 613: buf[0] = v >> 24; ! 614: buf[1] = v >> 16; ! 615: buf[2] = v >> 8; ! 616: buf[3] = v; ! 617: } else { ! 618: buf[3] = v >> 24; ! 619: buf[2] = v >> 16; ! 620: buf[1] = v >> 8; ! 621: buf[0] = v; ! 622: } ! 623: break; ! 624: } ! 625: } ! 626: ! 627: static void vnc_write_pixels_generic(VncState *vs, struct PixelFormat *pf, ! 628: void *pixels1, int size) ! 629: { ! 630: uint8_t buf[4]; ! 631: ! 632: if (pf->bytes_per_pixel == 4) { ! 633: uint32_t *pixels = pixels1; ! 634: int n, i; ! 635: n = size >> 2; ! 636: for(i = 0; i < n; i++) { ! 637: vnc_convert_pixel(vs, buf, pixels[i]); ! 638: vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel); ! 639: } ! 640: } else if (pf->bytes_per_pixel == 2) { ! 641: uint16_t *pixels = pixels1; ! 642: int n, i; ! 643: n = size >> 1; ! 644: for(i = 0; i < n; i++) { ! 645: vnc_convert_pixel(vs, buf, pixels[i]); ! 646: vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel); ! 647: } ! 648: } else if (pf->bytes_per_pixel == 1) { ! 649: uint8_t *pixels = pixels1; ! 650: int n, i; ! 651: n = size; ! 652: for(i = 0; i < n; i++) { ! 653: vnc_convert_pixel(vs, buf, pixels[i]); ! 654: vnc_write(vs, buf, vs->clientds.pf.bytes_per_pixel); ! 655: } ! 656: } else { ! 657: fprintf(stderr, "vnc_write_pixels_generic: VncState color depth not supported\n"); ! 658: } ! 659: } ! 660: ! 661: int vnc_raw_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) ! 662: { ! 663: int i; ! 664: uint8_t *row; ! 665: VncDisplay *vd = vs->vd; ! 666: ! 667: row = vd->server->data + y * ds_get_linesize(vs->ds) + x * ds_get_bytes_per_pixel(vs->ds); ! 668: for (i = 0; i < h; i++) { ! 669: vs->write_pixels(vs, &vd->server->pf, row, w * ds_get_bytes_per_pixel(vs->ds)); ! 670: row += ds_get_linesize(vs->ds); ! 671: } ! 672: return 1; ! 673: } ! 674: ! 675: int vnc_send_framebuffer_update(VncState *vs, int x, int y, int w, int h) ! 676: { ! 677: int n = 0; ! 678: ! 679: switch(vs->vnc_encoding) { ! 680: case VNC_ENCODING_ZLIB: ! 681: n = vnc_zlib_send_framebuffer_update(vs, x, y, w, h); ! 682: break; ! 683: case VNC_ENCODING_HEXTILE: ! 684: vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_HEXTILE); ! 685: n = vnc_hextile_send_framebuffer_update(vs, x, y, w, h); ! 686: break; ! 687: case VNC_ENCODING_TIGHT: ! 688: n = vnc_tight_send_framebuffer_update(vs, x, y, w, h); ! 689: break; ! 690: case VNC_ENCODING_TIGHT_PNG: ! 691: n = vnc_tight_png_send_framebuffer_update(vs, x, y, w, h); ! 692: break; ! 693: default: ! 694: vnc_framebuffer_update(vs, x, y, w, h, VNC_ENCODING_RAW); ! 695: n = vnc_raw_send_framebuffer_update(vs, x, y, w, h); ! 696: break; ! 697: } ! 698: return n; ! 699: } ! 700: ! 701: static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h) ! 702: { ! 703: /* send bitblit op to the vnc client */ ! 704: vnc_lock_output(vs); ! 705: vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); ! 706: vnc_write_u8(vs, 0); ! 707: vnc_write_u16(vs, 1); /* number of rects */ ! 708: vnc_framebuffer_update(vs, dst_x, dst_y, w, h, VNC_ENCODING_COPYRECT); ! 709: vnc_write_u16(vs, src_x); ! 710: vnc_write_u16(vs, src_y); ! 711: vnc_unlock_output(vs); ! 712: vnc_flush(vs); ! 713: } ! 714: ! 715: static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) ! 716: { ! 717: VncDisplay *vd = ds->opaque; ! 718: VncState *vs, *vn; ! 719: uint8_t *src_row; ! 720: uint8_t *dst_row; ! 721: int i,x,y,pitch,depth,inc,w_lim,s; ! 722: int cmp_bytes; ! 723: ! 724: vnc_refresh_server_surface(vd); ! 725: QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { ! 726: if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { ! 727: vs->force_update = 1; ! 728: vnc_update_client_sync(vs, 1); ! 729: /* vs might be free()ed here */ ! 730: } ! 731: } ! 732: ! 733: /* do bitblit op on the local surface too */ ! 734: pitch = ds_get_linesize(vd->ds); ! 735: depth = ds_get_bytes_per_pixel(vd->ds); ! 736: src_row = vd->server->data + pitch * src_y + depth * src_x; ! 737: dst_row = vd->server->data + pitch * dst_y + depth * dst_x; ! 738: y = dst_y; ! 739: inc = 1; ! 740: if (dst_y > src_y) { ! 741: /* copy backwards */ ! 742: src_row += pitch * (h-1); ! 743: dst_row += pitch * (h-1); ! 744: pitch = -pitch; ! 745: y = dst_y + h - 1; ! 746: inc = -1; ! 747: } ! 748: w_lim = w - (16 - (dst_x % 16)); ! 749: if (w_lim < 0) ! 750: w_lim = w; ! 751: else ! 752: w_lim = w - (w_lim % 16); ! 753: for (i = 0; i < h; i++) { ! 754: for (x = 0; x <= w_lim; ! 755: x += s, src_row += cmp_bytes, dst_row += cmp_bytes) { ! 756: if (x == w_lim) { ! 757: if ((s = w - w_lim) == 0) ! 758: break; ! 759: } else if (!x) { ! 760: s = (16 - (dst_x % 16)); ! 761: s = MIN(s, w_lim); ! 762: } else { ! 763: s = 16; ! 764: } ! 765: cmp_bytes = s * depth; ! 766: if (memcmp(src_row, dst_row, cmp_bytes) == 0) ! 767: continue; ! 768: memmove(dst_row, src_row, cmp_bytes); ! 769: QTAILQ_FOREACH(vs, &vd->clients, next) { ! 770: if (!vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { ! 771: vnc_set_bit(vs->dirty[y], ((x + dst_x) / 16)); ! 772: } ! 773: } ! 774: } ! 775: src_row += pitch - w * depth; ! 776: dst_row += pitch - w * depth; ! 777: y += inc; ! 778: } ! 779: ! 780: QTAILQ_FOREACH(vs, &vd->clients, next) { ! 781: if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) { ! 782: vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h); ! 783: } ! 784: } ! 785: } ! 786: ! 787: static void vnc_mouse_set(int x, int y, int visible) ! 788: { ! 789: /* can we ask the client(s) to move the pointer ??? */ ! 790: } ! 791: ! 792: static int vnc_cursor_define(VncState *vs) ! 793: { ! 794: QEMUCursor *c = vs->vd->cursor; ! 795: PixelFormat pf = qemu_default_pixelformat(32); ! 796: int isize; ! 797: ! 798: if (vnc_has_feature(vs, VNC_FEATURE_RICH_CURSOR)) { ! 799: vnc_lock_output(vs); ! 800: vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); ! 801: vnc_write_u8(vs, 0); /* padding */ ! 802: vnc_write_u16(vs, 1); /* # of rects */ ! 803: vnc_framebuffer_update(vs, c->hot_x, c->hot_y, c->width, c->height, ! 804: VNC_ENCODING_RICH_CURSOR); ! 805: isize = c->width * c->height * vs->clientds.pf.bytes_per_pixel; ! 806: vnc_write_pixels_generic(vs, &pf, c->data, isize); ! 807: vnc_write(vs, vs->vd->cursor_mask, vs->vd->cursor_msize); ! 808: vnc_unlock_output(vs); ! 809: return 0; ! 810: } ! 811: return -1; ! 812: } ! 813: ! 814: static void vnc_dpy_cursor_define(QEMUCursor *c) ! 815: { ! 816: VncDisplay *vd = vnc_display; ! 817: VncState *vs; ! 818: ! 819: cursor_put(vd->cursor); ! 820: qemu_free(vd->cursor_mask); ! 821: ! 822: vd->cursor = c; ! 823: cursor_get(vd->cursor); ! 824: vd->cursor_msize = cursor_get_mono_bpl(c) * c->height; ! 825: vd->cursor_mask = qemu_mallocz(vd->cursor_msize); ! 826: cursor_get_mono_mask(c, 0, vd->cursor_mask); ! 827: ! 828: QTAILQ_FOREACH(vs, &vd->clients, next) { ! 829: vnc_cursor_define(vs); ! 830: } ! 831: } ! 832: ! 833: static int find_and_clear_dirty_height(struct VncState *vs, ! 834: int y, int last_x, int x) ! 835: { ! 836: int h; ! 837: VncDisplay *vd = vs->vd; ! 838: ! 839: for (h = 1; h < (vd->server->height - y); h++) { ! 840: int tmp_x; ! 841: if (!vnc_get_bit(vs->dirty[y + h], last_x)) ! 842: break; ! 843: for (tmp_x = last_x; tmp_x < x; tmp_x++) ! 844: vnc_clear_bit(vs->dirty[y + h], tmp_x); ! 845: } ! 846: ! 847: return h; ! 848: } ! 849: ! 850: #ifdef CONFIG_VNC_THREAD ! 851: static int vnc_update_client_sync(VncState *vs, int has_dirty) ! 852: { ! 853: int ret = vnc_update_client(vs, has_dirty); ! 854: vnc_jobs_join(vs); ! 855: return ret; ! 856: } ! 857: #else ! 858: static int vnc_update_client_sync(VncState *vs, int has_dirty) ! 859: { ! 860: return vnc_update_client(vs, has_dirty); ! 861: } ! 862: #endif ! 863: ! 864: static int vnc_update_client(VncState *vs, int has_dirty) ! 865: { ! 866: if (vs->need_update && vs->csock != -1) { ! 867: VncDisplay *vd = vs->vd; ! 868: VncJob *job; ! 869: int y; ! 870: int width, height; ! 871: int n = 0; ! 872: ! 873: ! 874: if (vs->output.offset && !vs->audio_cap && !vs->force_update) ! 875: /* kernel send buffers are full -> drop frames to throttle */ ! 876: return 0; ! 877: ! 878: if (!has_dirty && !vs->audio_cap && !vs->force_update) ! 879: return 0; ! 880: ! 881: /* ! 882: * Send screen updates to the vnc client using the server ! 883: * surface and server dirty map. guest surface updates ! 884: * happening in parallel don't disturb us, the next pass will ! 885: * send them to the client. ! 886: */ ! 887: job = vnc_job_new(vs); ! 888: ! 889: width = MIN(vd->server->width, vs->client_width); ! 890: height = MIN(vd->server->height, vs->client_height); ! 891: ! 892: for (y = 0; y < height; y++) { ! 893: int x; ! 894: int last_x = -1; ! 895: for (x = 0; x < width / 16; x++) { ! 896: if (vnc_get_bit(vs->dirty[y], x)) { ! 897: if (last_x == -1) { ! 898: last_x = x; ! 899: } ! 900: vnc_clear_bit(vs->dirty[y], x); ! 901: } else { ! 902: if (last_x != -1) { ! 903: int h = find_and_clear_dirty_height(vs, y, last_x, x); ! 904: ! 905: n += vnc_job_add_rect(job, last_x * 16, y, ! 906: (x - last_x) * 16, h); ! 907: } ! 908: last_x = -1; ! 909: } ! 910: } ! 911: if (last_x != -1) { ! 912: int h = find_and_clear_dirty_height(vs, y, last_x, x); ! 913: n += vnc_job_add_rect(job, last_x * 16, y, ! 914: (x - last_x) * 16, h); ! 915: } ! 916: } ! 917: ! 918: vnc_job_push(job); ! 919: vs->force_update = 0; ! 920: return n; ! 921: } ! 922: ! 923: if (vs->csock == -1) ! 924: vnc_disconnect_finish(vs); ! 925: ! 926: return 0; ! 927: } ! 928: ! 929: /* audio */ ! 930: static void audio_capture_notify(void *opaque, audcnotification_e cmd) ! 931: { ! 932: VncState *vs = opaque; ! 933: ! 934: switch (cmd) { ! 935: case AUD_CNOTIFY_DISABLE: ! 936: vnc_lock_output(vs); ! 937: vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); ! 938: vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); ! 939: vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_END); ! 940: vnc_unlock_output(vs); ! 941: vnc_flush(vs); ! 942: break; ! 943: ! 944: case AUD_CNOTIFY_ENABLE: ! 945: vnc_lock_output(vs); ! 946: vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); ! 947: vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); ! 948: vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_BEGIN); ! 949: vnc_unlock_output(vs); ! 950: vnc_flush(vs); ! 951: break; ! 952: } ! 953: } ! 954: ! 955: static void audio_capture_destroy(void *opaque) ! 956: { ! 957: } ! 958: ! 959: static void audio_capture(void *opaque, void *buf, int size) ! 960: { ! 961: VncState *vs = opaque; ! 962: ! 963: vnc_lock_output(vs); ! 964: vnc_write_u8(vs, VNC_MSG_SERVER_QEMU); ! 965: vnc_write_u8(vs, VNC_MSG_SERVER_QEMU_AUDIO); ! 966: vnc_write_u16(vs, VNC_MSG_SERVER_QEMU_AUDIO_DATA); ! 967: vnc_write_u32(vs, size); ! 968: vnc_write(vs, buf, size); ! 969: vnc_unlock_output(vs); ! 970: vnc_flush(vs); ! 971: } ! 972: ! 973: static void audio_add(VncState *vs) ! 974: { ! 975: struct audio_capture_ops ops; ! 976: ! 977: if (vs->audio_cap) { ! 978: monitor_printf(default_mon, "audio already running\n"); ! 979: return; ! 980: } ! 981: ! 982: ops.notify = audio_capture_notify; ! 983: ops.destroy = audio_capture_destroy; ! 984: ops.capture = audio_capture; ! 985: ! 986: vs->audio_cap = AUD_add_capture(&vs->as, &ops, vs); ! 987: if (!vs->audio_cap) { ! 988: monitor_printf(default_mon, "Failed to add audio capture\n"); ! 989: } ! 990: } ! 991: ! 992: static void audio_del(VncState *vs) ! 993: { ! 994: if (vs->audio_cap) { ! 995: AUD_del_capture(vs->audio_cap, vs); ! 996: vs->audio_cap = NULL; ! 997: } ! 998: } ! 999: ! 1000: static void vnc_disconnect_start(VncState *vs) ! 1001: { ! 1002: if (vs->csock == -1) ! 1003: return; ! 1004: qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); ! 1005: closesocket(vs->csock); ! 1006: vs->csock = -1; ! 1007: } ! 1008: ! 1009: static void vnc_disconnect_finish(VncState *vs) ! 1010: { ! 1011: vnc_jobs_join(vs); /* Wait encoding jobs */ ! 1012: ! 1013: vnc_lock_output(vs); ! 1014: vnc_qmp_event(vs, QEVENT_VNC_DISCONNECTED); ! 1015: ! 1016: buffer_free(&vs->input); ! 1017: buffer_free(&vs->output); ! 1018: ! 1019: qobject_decref(vs->info); ! 1020: ! 1021: vnc_zlib_clear(vs); ! 1022: vnc_tight_clear(vs); ! 1023: ! 1024: #ifdef CONFIG_VNC_TLS ! 1025: vnc_tls_client_cleanup(vs); ! 1026: #endif /* CONFIG_VNC_TLS */ ! 1027: #ifdef CONFIG_VNC_SASL ! 1028: vnc_sasl_client_cleanup(vs); ! 1029: #endif /* CONFIG_VNC_SASL */ ! 1030: audio_del(vs); ! 1031: ! 1032: QTAILQ_REMOVE(&vs->vd->clients, vs, next); ! 1033: ! 1034: if (QTAILQ_EMPTY(&vs->vd->clients)) { ! 1035: dcl->idle = 1; ! 1036: } ! 1037: ! 1038: qemu_remove_mouse_mode_change_notifier(&vs->mouse_mode_notifier); ! 1039: vnc_remove_timer(vs->vd); ! 1040: if (vs->vd->lock_key_sync) ! 1041: qemu_remove_led_event_handler(vs->led); ! 1042: vnc_unlock_output(vs); ! 1043: ! 1044: #ifdef CONFIG_VNC_THREAD ! 1045: qemu_mutex_destroy(&vs->output_mutex); ! 1046: #endif ! 1047: qemu_free(vs); ! 1048: } ! 1049: ! 1050: int vnc_client_io_error(VncState *vs, int ret, int last_errno) ! 1051: { ! 1052: if (ret == 0 || ret == -1) { ! 1053: if (ret == -1) { ! 1054: switch (last_errno) { ! 1055: case EINTR: ! 1056: case EAGAIN: ! 1057: #ifdef _WIN32 ! 1058: case WSAEWOULDBLOCK: ! 1059: #endif ! 1060: return 0; ! 1061: default: ! 1062: break; ! 1063: } ! 1064: } ! 1065: ! 1066: VNC_DEBUG("Closing down client sock: ret %d, errno %d\n", ! 1067: ret, ret < 0 ? last_errno : 0); ! 1068: vnc_disconnect_start(vs); ! 1069: ! 1070: return 0; ! 1071: } ! 1072: return ret; ! 1073: } ! 1074: ! 1075: ! 1076: void vnc_client_error(VncState *vs) ! 1077: { ! 1078: VNC_DEBUG("Closing down client sock: protocol error\n"); ! 1079: vnc_disconnect_start(vs); ! 1080: } ! 1081: ! 1082: ! 1083: /* ! 1084: * Called to write a chunk of data to the client socket. The data may ! 1085: * be the raw data, or may have already been encoded by SASL. ! 1086: * The data will be written either straight onto the socket, or ! 1087: * written via the GNUTLS wrappers, if TLS/SSL encryption is enabled ! 1088: * ! 1089: * NB, it is theoretically possible to have 2 layers of encryption, ! 1090: * both SASL, and this TLS layer. It is highly unlikely in practice ! 1091: * though, since SASL encryption will typically be a no-op if TLS ! 1092: * is active ! 1093: * ! 1094: * Returns the number of bytes written, which may be less than ! 1095: * the requested 'datalen' if the socket would block. Returns ! 1096: * -1 on error, and disconnects the client socket. ! 1097: */ ! 1098: long vnc_client_write_buf(VncState *vs, const uint8_t *data, size_t datalen) ! 1099: { ! 1100: long ret; ! 1101: #ifdef CONFIG_VNC_TLS ! 1102: if (vs->tls.session) { ! 1103: ret = gnutls_write(vs->tls.session, data, datalen); ! 1104: if (ret < 0) { ! 1105: if (ret == GNUTLS_E_AGAIN) ! 1106: errno = EAGAIN; ! 1107: else ! 1108: errno = EIO; ! 1109: ret = -1; ! 1110: } ! 1111: } else ! 1112: #endif /* CONFIG_VNC_TLS */ ! 1113: ret = send(vs->csock, (const void *)data, datalen, 0); ! 1114: VNC_DEBUG("Wrote wire %p %zd -> %ld\n", data, datalen, ret); ! 1115: return vnc_client_io_error(vs, ret, socket_error()); ! 1116: } ! 1117: ! 1118: ! 1119: /* ! 1120: * Called to write buffered data to the client socket, when not ! 1121: * using any SASL SSF encryption layers. Will write as much data ! 1122: * as possible without blocking. If all buffered data is written, ! 1123: * will switch the FD poll() handler back to read monitoring. ! 1124: * ! 1125: * Returns the number of bytes written, which may be less than ! 1126: * the buffered output data if the socket would block. Returns ! 1127: * -1 on error, and disconnects the client socket. ! 1128: */ ! 1129: static long vnc_client_write_plain(VncState *vs) ! 1130: { ! 1131: long ret; ! 1132: ! 1133: #ifdef CONFIG_VNC_SASL ! 1134: VNC_DEBUG("Write Plain: Pending output %p size %zd offset %zd. Wait SSF %d\n", ! 1135: vs->output.buffer, vs->output.capacity, vs->output.offset, ! 1136: vs->sasl.waitWriteSSF); ! 1137: ! 1138: if (vs->sasl.conn && ! 1139: vs->sasl.runSSF && ! 1140: vs->sasl.waitWriteSSF) { ! 1141: ret = vnc_client_write_buf(vs, vs->output.buffer, vs->sasl.waitWriteSSF); ! 1142: if (ret) ! 1143: vs->sasl.waitWriteSSF -= ret; ! 1144: } else ! 1145: #endif /* CONFIG_VNC_SASL */ ! 1146: ret = vnc_client_write_buf(vs, vs->output.buffer, vs->output.offset); ! 1147: if (!ret) ! 1148: return 0; ! 1149: ! 1150: memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret)); ! 1151: vs->output.offset -= ret; ! 1152: ! 1153: if (vs->output.offset == 0) { ! 1154: qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); ! 1155: } ! 1156: ! 1157: return ret; ! 1158: } ! 1159: ! 1160: ! 1161: /* ! 1162: * First function called whenever there is data to be written to ! 1163: * the client socket. Will delegate actual work according to whether ! 1164: * SASL SSF layers are enabled (thus requiring encryption calls) ! 1165: */ ! 1166: static void vnc_client_write_locked(void *opaque) ! 1167: { ! 1168: VncState *vs = opaque; ! 1169: ! 1170: #ifdef CONFIG_VNC_SASL ! 1171: if (vs->sasl.conn && ! 1172: vs->sasl.runSSF && ! 1173: !vs->sasl.waitWriteSSF) { ! 1174: vnc_client_write_sasl(vs); ! 1175: } else ! 1176: #endif /* CONFIG_VNC_SASL */ ! 1177: vnc_client_write_plain(vs); ! 1178: } ! 1179: ! 1180: void vnc_client_write(void *opaque) ! 1181: { ! 1182: VncState *vs = opaque; ! 1183: ! 1184: vnc_lock_output(vs); ! 1185: if (vs->output.offset) { ! 1186: vnc_client_write_locked(opaque); ! 1187: } else if (vs->csock != -1) { ! 1188: qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); ! 1189: } ! 1190: vnc_unlock_output(vs); ! 1191: } ! 1192: ! 1193: void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) ! 1194: { ! 1195: vs->read_handler = func; ! 1196: vs->read_handler_expect = expecting; ! 1197: } ! 1198: ! 1199: ! 1200: /* ! 1201: * Called to read a chunk of data from the client socket. The data may ! 1202: * be the raw data, or may need to be further decoded by SASL. ! 1203: * The data will be read either straight from to the socket, or ! 1204: * read via the GNUTLS wrappers, if TLS/SSL encryption is enabled ! 1205: * ! 1206: * NB, it is theoretically possible to have 2 layers of encryption, ! 1207: * both SASL, and this TLS layer. It is highly unlikely in practice ! 1208: * though, since SASL encryption will typically be a no-op if TLS ! 1209: * is active ! 1210: * ! 1211: * Returns the number of bytes read, which may be less than ! 1212: * the requested 'datalen' if the socket would block. Returns ! 1213: * -1 on error, and disconnects the client socket. ! 1214: */ ! 1215: long vnc_client_read_buf(VncState *vs, uint8_t *data, size_t datalen) ! 1216: { ! 1217: long ret; ! 1218: #ifdef CONFIG_VNC_TLS ! 1219: if (vs->tls.session) { ! 1220: ret = gnutls_read(vs->tls.session, data, datalen); ! 1221: if (ret < 0) { ! 1222: if (ret == GNUTLS_E_AGAIN) ! 1223: errno = EAGAIN; ! 1224: else ! 1225: errno = EIO; ! 1226: ret = -1; ! 1227: } ! 1228: } else ! 1229: #endif /* CONFIG_VNC_TLS */ ! 1230: ret = recv(vs->csock, (void *)data, datalen, 0); ! 1231: VNC_DEBUG("Read wire %p %zd -> %ld\n", data, datalen, ret); ! 1232: return vnc_client_io_error(vs, ret, socket_error()); ! 1233: } ! 1234: ! 1235: ! 1236: /* ! 1237: * Called to read data from the client socket to the input buffer, ! 1238: * when not using any SASL SSF encryption layers. Will read as much ! 1239: * data as possible without blocking. ! 1240: * ! 1241: * Returns the number of bytes read. Returns -1 on error, and ! 1242: * disconnects the client socket. ! 1243: */ ! 1244: static long vnc_client_read_plain(VncState *vs) ! 1245: { ! 1246: int ret; ! 1247: VNC_DEBUG("Read plain %p size %zd offset %zd\n", ! 1248: vs->input.buffer, vs->input.capacity, vs->input.offset); ! 1249: buffer_reserve(&vs->input, 4096); ! 1250: ret = vnc_client_read_buf(vs, buffer_end(&vs->input), 4096); ! 1251: if (!ret) ! 1252: return 0; ! 1253: vs->input.offset += ret; ! 1254: return ret; ! 1255: } ! 1256: ! 1257: ! 1258: /* ! 1259: * First function called whenever there is more data to be read from ! 1260: * the client socket. Will delegate actual work according to whether ! 1261: * SASL SSF layers are enabled (thus requiring decryption calls) ! 1262: */ ! 1263: void vnc_client_read(void *opaque) ! 1264: { ! 1265: VncState *vs = opaque; ! 1266: long ret; ! 1267: ! 1268: #ifdef CONFIG_VNC_SASL ! 1269: if (vs->sasl.conn && vs->sasl.runSSF) ! 1270: ret = vnc_client_read_sasl(vs); ! 1271: else ! 1272: #endif /* CONFIG_VNC_SASL */ ! 1273: ret = vnc_client_read_plain(vs); ! 1274: if (!ret) { ! 1275: if (vs->csock == -1) ! 1276: vnc_disconnect_finish(vs); ! 1277: return; ! 1278: } ! 1279: ! 1280: while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) { ! 1281: size_t len = vs->read_handler_expect; ! 1282: int ret; ! 1283: ! 1284: ret = vs->read_handler(vs, vs->input.buffer, len); ! 1285: if (vs->csock == -1) { ! 1286: vnc_disconnect_finish(vs); ! 1287: return; ! 1288: } ! 1289: ! 1290: if (!ret) { ! 1291: memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len)); ! 1292: vs->input.offset -= len; ! 1293: } else { ! 1294: vs->read_handler_expect = ret; ! 1295: } ! 1296: } ! 1297: } ! 1298: ! 1299: void vnc_write(VncState *vs, const void *data, size_t len) ! 1300: { ! 1301: buffer_reserve(&vs->output, len); ! 1302: ! 1303: if (vs->csock != -1 && buffer_empty(&vs->output)) { ! 1304: qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs); ! 1305: } ! 1306: ! 1307: buffer_append(&vs->output, data, len); ! 1308: } ! 1309: ! 1310: void vnc_write_s32(VncState *vs, int32_t value) ! 1311: { ! 1312: vnc_write_u32(vs, *(uint32_t *)&value); ! 1313: } ! 1314: ! 1315: void vnc_write_u32(VncState *vs, uint32_t value) ! 1316: { ! 1317: uint8_t buf[4]; ! 1318: ! 1319: buf[0] = (value >> 24) & 0xFF; ! 1320: buf[1] = (value >> 16) & 0xFF; ! 1321: buf[2] = (value >> 8) & 0xFF; ! 1322: buf[3] = value & 0xFF; ! 1323: ! 1324: vnc_write(vs, buf, 4); ! 1325: } ! 1326: ! 1327: void vnc_write_u16(VncState *vs, uint16_t value) ! 1328: { ! 1329: uint8_t buf[2]; ! 1330: ! 1331: buf[0] = (value >> 8) & 0xFF; ! 1332: buf[1] = value & 0xFF; ! 1333: ! 1334: vnc_write(vs, buf, 2); ! 1335: } ! 1336: ! 1337: void vnc_write_u8(VncState *vs, uint8_t value) ! 1338: { ! 1339: vnc_write(vs, (char *)&value, 1); ! 1340: } ! 1341: ! 1342: void vnc_flush(VncState *vs) ! 1343: { ! 1344: vnc_lock_output(vs); ! 1345: if (vs->csock != -1 && vs->output.offset) { ! 1346: vnc_client_write_locked(vs); ! 1347: } ! 1348: vnc_unlock_output(vs); ! 1349: } ! 1350: ! 1351: uint8_t read_u8(uint8_t *data, size_t offset) ! 1352: { ! 1353: return data[offset]; ! 1354: } ! 1355: ! 1356: uint16_t read_u16(uint8_t *data, size_t offset) ! 1357: { ! 1358: return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); ! 1359: } ! 1360: ! 1361: int32_t read_s32(uint8_t *data, size_t offset) ! 1362: { ! 1363: return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) | ! 1364: (data[offset + 2] << 8) | data[offset + 3]); ! 1365: } ! 1366: ! 1367: uint32_t read_u32(uint8_t *data, size_t offset) ! 1368: { ! 1369: return ((data[offset] << 24) | (data[offset + 1] << 16) | ! 1370: (data[offset + 2] << 8) | data[offset + 3]); ! 1371: } ! 1372: ! 1373: static void client_cut_text(VncState *vs, size_t len, uint8_t *text) ! 1374: { ! 1375: } ! 1376: ! 1377: static void check_pointer_type_change(Notifier *notifier) ! 1378: { ! 1379: VncState *vs = container_of(notifier, VncState, mouse_mode_notifier); ! 1380: int absolute = kbd_mouse_is_absolute(); ! 1381: ! 1382: if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE) && vs->absolute != absolute) { ! 1383: vnc_lock_output(vs); ! 1384: vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); ! 1385: vnc_write_u8(vs, 0); ! 1386: vnc_write_u16(vs, 1); ! 1387: vnc_framebuffer_update(vs, absolute, 0, ! 1388: ds_get_width(vs->ds), ds_get_height(vs->ds), ! 1389: VNC_ENCODING_POINTER_TYPE_CHANGE); ! 1390: vnc_unlock_output(vs); ! 1391: vnc_flush(vs); ! 1392: } ! 1393: vs->absolute = absolute; ! 1394: } ! 1395: ! 1396: static void pointer_event(VncState *vs, int button_mask, int x, int y) ! 1397: { ! 1398: int buttons = 0; ! 1399: int dz = 0; ! 1400: ! 1401: if (button_mask & 0x01) ! 1402: buttons |= MOUSE_EVENT_LBUTTON; ! 1403: if (button_mask & 0x02) ! 1404: buttons |= MOUSE_EVENT_MBUTTON; ! 1405: if (button_mask & 0x04) ! 1406: buttons |= MOUSE_EVENT_RBUTTON; ! 1407: if (button_mask & 0x08) ! 1408: dz = -1; ! 1409: if (button_mask & 0x10) ! 1410: dz = 1; ! 1411: ! 1412: if (vs->absolute) { ! 1413: kbd_mouse_event(ds_get_width(vs->ds) > 1 ? ! 1414: x * 0x7FFF / (ds_get_width(vs->ds) - 1) : 0x4000, ! 1415: ds_get_height(vs->ds) > 1 ? ! 1416: y * 0x7FFF / (ds_get_height(vs->ds) - 1) : 0x4000, ! 1417: dz, buttons); ! 1418: } else if (vnc_has_feature(vs, VNC_FEATURE_POINTER_TYPE_CHANGE)) { ! 1419: x -= 0x7FFF; ! 1420: y -= 0x7FFF; ! 1421: ! 1422: kbd_mouse_event(x, y, dz, buttons); ! 1423: } else { ! 1424: if (vs->last_x != -1) ! 1425: kbd_mouse_event(x - vs->last_x, ! 1426: y - vs->last_y, ! 1427: dz, buttons); ! 1428: vs->last_x = x; ! 1429: vs->last_y = y; ! 1430: } ! 1431: } ! 1432: ! 1433: static void reset_keys(VncState *vs) ! 1434: { ! 1435: int i; ! 1436: for(i = 0; i < 256; i++) { ! 1437: if (vs->modifiers_state[i]) { ! 1438: if (i & SCANCODE_GREY) ! 1439: kbd_put_keycode(SCANCODE_EMUL0); ! 1440: kbd_put_keycode(i | SCANCODE_UP); ! 1441: vs->modifiers_state[i] = 0; ! 1442: } ! 1443: } ! 1444: } ! 1445: ! 1446: static void press_key(VncState *vs, int keysym) ! 1447: { ! 1448: int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK; ! 1449: if (keycode & SCANCODE_GREY) ! 1450: kbd_put_keycode(SCANCODE_EMUL0); ! 1451: kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); ! 1452: if (keycode & SCANCODE_GREY) ! 1453: kbd_put_keycode(SCANCODE_EMUL0); ! 1454: kbd_put_keycode(keycode | SCANCODE_UP); ! 1455: } ! 1456: ! 1457: static void kbd_leds(void *opaque, int ledstate) ! 1458: { ! 1459: VncState *vs = opaque; ! 1460: int caps, num; ! 1461: ! 1462: caps = ledstate & QEMU_CAPS_LOCK_LED ? 1 : 0; ! 1463: num = ledstate & QEMU_NUM_LOCK_LED ? 1 : 0; ! 1464: ! 1465: if (vs->modifiers_state[0x3a] != caps) { ! 1466: vs->modifiers_state[0x3a] = caps; ! 1467: } ! 1468: if (vs->modifiers_state[0x45] != num) { ! 1469: vs->modifiers_state[0x45] = num; ! 1470: } ! 1471: } ! 1472: ! 1473: static void do_key_event(VncState *vs, int down, int keycode, int sym) ! 1474: { ! 1475: /* QEMU console switch */ ! 1476: switch(keycode) { ! 1477: case 0x2a: /* Left Shift */ ! 1478: case 0x36: /* Right Shift */ ! 1479: case 0x1d: /* Left CTRL */ ! 1480: case 0x9d: /* Right CTRL */ ! 1481: case 0x38: /* Left ALT */ ! 1482: case 0xb8: /* Right ALT */ ! 1483: if (down) ! 1484: vs->modifiers_state[keycode] = 1; ! 1485: else ! 1486: vs->modifiers_state[keycode] = 0; ! 1487: break; ! 1488: case 0x02 ... 0x0a: /* '1' to '9' keys */ ! 1489: if (down && vs->modifiers_state[0x1d] && vs->modifiers_state[0x38]) { ! 1490: /* Reset the modifiers sent to the current console */ ! 1491: reset_keys(vs); ! 1492: console_select(keycode - 0x02); ! 1493: return; ! 1494: } ! 1495: break; ! 1496: case 0x3a: /* CapsLock */ ! 1497: case 0x45: /* NumLock */ ! 1498: if (down) ! 1499: vs->modifiers_state[keycode] ^= 1; ! 1500: break; ! 1501: } ! 1502: ! 1503: if (vs->vd->lock_key_sync && ! 1504: keycode_is_keypad(vs->vd->kbd_layout, keycode)) { ! 1505: /* If the numlock state needs to change then simulate an additional ! 1506: keypress before sending this one. This will happen if the user ! 1507: toggles numlock away from the VNC window. ! 1508: */ ! 1509: if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) { ! 1510: if (!vs->modifiers_state[0x45]) { ! 1511: vs->modifiers_state[0x45] = 1; ! 1512: press_key(vs, 0xff7f); ! 1513: } ! 1514: } else { ! 1515: if (vs->modifiers_state[0x45]) { ! 1516: vs->modifiers_state[0x45] = 0; ! 1517: press_key(vs, 0xff7f); ! 1518: } ! 1519: } ! 1520: } ! 1521: ! 1522: if (vs->vd->lock_key_sync && ! 1523: ((sym >= 'A' && sym <= 'Z') || (sym >= 'a' && sym <= 'z'))) { ! 1524: /* If the capslock state needs to change then simulate an additional ! 1525: keypress before sending this one. This will happen if the user ! 1526: toggles capslock away from the VNC window. ! 1527: */ ! 1528: int uppercase = !!(sym >= 'A' && sym <= 'Z'); ! 1529: int shift = !!(vs->modifiers_state[0x2a] | vs->modifiers_state[0x36]); ! 1530: int capslock = !!(vs->modifiers_state[0x3a]); ! 1531: if (capslock) { ! 1532: if (uppercase == shift) { ! 1533: vs->modifiers_state[0x3a] = 0; ! 1534: press_key(vs, 0xffe5); ! 1535: } ! 1536: } else { ! 1537: if (uppercase != shift) { ! 1538: vs->modifiers_state[0x3a] = 1; ! 1539: press_key(vs, 0xffe5); ! 1540: } ! 1541: } ! 1542: } ! 1543: ! 1544: if (is_graphic_console()) { ! 1545: if (keycode & SCANCODE_GREY) ! 1546: kbd_put_keycode(SCANCODE_EMUL0); ! 1547: if (down) ! 1548: kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK); ! 1549: else ! 1550: kbd_put_keycode(keycode | SCANCODE_UP); ! 1551: } else { ! 1552: /* QEMU console emulation */ ! 1553: if (down) { ! 1554: int numlock = vs->modifiers_state[0x45]; ! 1555: switch (keycode) { ! 1556: case 0x2a: /* Left Shift */ ! 1557: case 0x36: /* Right Shift */ ! 1558: case 0x1d: /* Left CTRL */ ! 1559: case 0x9d: /* Right CTRL */ ! 1560: case 0x38: /* Left ALT */ ! 1561: case 0xb8: /* Right ALT */ ! 1562: break; ! 1563: case 0xc8: ! 1564: kbd_put_keysym(QEMU_KEY_UP); ! 1565: break; ! 1566: case 0xd0: ! 1567: kbd_put_keysym(QEMU_KEY_DOWN); ! 1568: break; ! 1569: case 0xcb: ! 1570: kbd_put_keysym(QEMU_KEY_LEFT); ! 1571: break; ! 1572: case 0xcd: ! 1573: kbd_put_keysym(QEMU_KEY_RIGHT); ! 1574: break; ! 1575: case 0xd3: ! 1576: kbd_put_keysym(QEMU_KEY_DELETE); ! 1577: break; ! 1578: case 0xc7: ! 1579: kbd_put_keysym(QEMU_KEY_HOME); ! 1580: break; ! 1581: case 0xcf: ! 1582: kbd_put_keysym(QEMU_KEY_END); ! 1583: break; ! 1584: case 0xc9: ! 1585: kbd_put_keysym(QEMU_KEY_PAGEUP); ! 1586: break; ! 1587: case 0xd1: ! 1588: kbd_put_keysym(QEMU_KEY_PAGEDOWN); ! 1589: break; ! 1590: ! 1591: case 0x47: ! 1592: kbd_put_keysym(numlock ? '7' : QEMU_KEY_HOME); ! 1593: break; ! 1594: case 0x48: ! 1595: kbd_put_keysym(numlock ? '8' : QEMU_KEY_UP); ! 1596: break; ! 1597: case 0x49: ! 1598: kbd_put_keysym(numlock ? '9' : QEMU_KEY_PAGEUP); ! 1599: break; ! 1600: case 0x4b: ! 1601: kbd_put_keysym(numlock ? '4' : QEMU_KEY_LEFT); ! 1602: break; ! 1603: case 0x4c: ! 1604: kbd_put_keysym('5'); ! 1605: break; ! 1606: case 0x4d: ! 1607: kbd_put_keysym(numlock ? '6' : QEMU_KEY_RIGHT); ! 1608: break; ! 1609: case 0x4f: ! 1610: kbd_put_keysym(numlock ? '1' : QEMU_KEY_END); ! 1611: break; ! 1612: case 0x50: ! 1613: kbd_put_keysym(numlock ? '2' : QEMU_KEY_DOWN); ! 1614: break; ! 1615: case 0x51: ! 1616: kbd_put_keysym(numlock ? '3' : QEMU_KEY_PAGEDOWN); ! 1617: break; ! 1618: case 0x52: ! 1619: kbd_put_keysym('0'); ! 1620: break; ! 1621: case 0x53: ! 1622: kbd_put_keysym(numlock ? '.' : QEMU_KEY_DELETE); ! 1623: break; ! 1624: ! 1625: case 0xb5: ! 1626: kbd_put_keysym('/'); ! 1627: break; ! 1628: case 0x37: ! 1629: kbd_put_keysym('*'); ! 1630: break; ! 1631: case 0x4a: ! 1632: kbd_put_keysym('-'); ! 1633: break; ! 1634: case 0x4e: ! 1635: kbd_put_keysym('+'); ! 1636: break; ! 1637: case 0x9c: ! 1638: kbd_put_keysym('\n'); ! 1639: break; ! 1640: ! 1641: default: ! 1642: kbd_put_keysym(sym); ! 1643: break; ! 1644: } ! 1645: } ! 1646: } ! 1647: } ! 1648: ! 1649: static void key_event(VncState *vs, int down, uint32_t sym) ! 1650: { ! 1651: int keycode; ! 1652: int lsym = sym; ! 1653: ! 1654: if (lsym >= 'A' && lsym <= 'Z' && is_graphic_console()) { ! 1655: lsym = lsym - 'A' + 'a'; ! 1656: } ! 1657: ! 1658: keycode = keysym2scancode(vs->vd->kbd_layout, lsym & 0xFFFF) & SCANCODE_KEYMASK; ! 1659: do_key_event(vs, down, keycode, sym); ! 1660: } ! 1661: ! 1662: static void ext_key_event(VncState *vs, int down, ! 1663: uint32_t sym, uint16_t keycode) ! 1664: { ! 1665: /* if the user specifies a keyboard layout, always use it */ ! 1666: if (keyboard_layout) ! 1667: key_event(vs, down, sym); ! 1668: else ! 1669: do_key_event(vs, down, keycode, sym); ! 1670: } ! 1671: ! 1672: static void framebuffer_update_request(VncState *vs, int incremental, ! 1673: int x_position, int y_position, ! 1674: int w, int h) ! 1675: { ! 1676: if (y_position > ds_get_height(vs->ds)) ! 1677: y_position = ds_get_height(vs->ds); ! 1678: if (y_position + h >= ds_get_height(vs->ds)) ! 1679: h = ds_get_height(vs->ds) - y_position; ! 1680: ! 1681: int i; ! 1682: vs->need_update = 1; ! 1683: if (!incremental) { ! 1684: vs->force_update = 1; ! 1685: for (i = 0; i < h; i++) { ! 1686: vnc_set_bits(vs->dirty[y_position + i], ! 1687: (ds_get_width(vs->ds) / 16), VNC_DIRTY_WORDS); ! 1688: } ! 1689: } ! 1690: } ! 1691: ! 1692: static void send_ext_key_event_ack(VncState *vs) ! 1693: { ! 1694: vnc_lock_output(vs); ! 1695: vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); ! 1696: vnc_write_u8(vs, 0); ! 1697: vnc_write_u16(vs, 1); ! 1698: vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), ! 1699: VNC_ENCODING_EXT_KEY_EVENT); ! 1700: vnc_unlock_output(vs); ! 1701: vnc_flush(vs); ! 1702: } ! 1703: ! 1704: static void send_ext_audio_ack(VncState *vs) ! 1705: { ! 1706: vnc_lock_output(vs); ! 1707: vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); ! 1708: vnc_write_u8(vs, 0); ! 1709: vnc_write_u16(vs, 1); ! 1710: vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ds_get_height(vs->ds), ! 1711: VNC_ENCODING_AUDIO); ! 1712: vnc_unlock_output(vs); ! 1713: vnc_flush(vs); ! 1714: } ! 1715: ! 1716: static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) ! 1717: { ! 1718: int i; ! 1719: unsigned int enc = 0; ! 1720: ! 1721: vs->features = 0; ! 1722: vs->vnc_encoding = 0; ! 1723: vs->tight.compression = 9; ! 1724: vs->tight.quality = -1; /* Lossless by default */ ! 1725: vs->absolute = -1; ! 1726: ! 1727: /* ! 1728: * Start from the end because the encodings are sent in order of preference. ! 1729: * This way the prefered encoding (first encoding defined in the array) ! 1730: * will be set at the end of the loop. ! 1731: */ ! 1732: for (i = n_encodings - 1; i >= 0; i--) { ! 1733: enc = encodings[i]; ! 1734: switch (enc) { ! 1735: case VNC_ENCODING_RAW: ! 1736: vs->vnc_encoding = enc; ! 1737: break; ! 1738: case VNC_ENCODING_COPYRECT: ! 1739: vs->features |= VNC_FEATURE_COPYRECT_MASK; ! 1740: break; ! 1741: case VNC_ENCODING_HEXTILE: ! 1742: vs->features |= VNC_FEATURE_HEXTILE_MASK; ! 1743: vs->vnc_encoding = enc; ! 1744: break; ! 1745: case VNC_ENCODING_TIGHT: ! 1746: vs->features |= VNC_FEATURE_TIGHT_MASK; ! 1747: vs->vnc_encoding = enc; ! 1748: break; ! 1749: case VNC_ENCODING_TIGHT_PNG: ! 1750: vs->features |= VNC_FEATURE_TIGHT_PNG_MASK; ! 1751: vs->vnc_encoding = enc; ! 1752: break; ! 1753: case VNC_ENCODING_ZLIB: ! 1754: vs->features |= VNC_FEATURE_ZLIB_MASK; ! 1755: vs->vnc_encoding = enc; ! 1756: break; ! 1757: case VNC_ENCODING_DESKTOPRESIZE: ! 1758: vs->features |= VNC_FEATURE_RESIZE_MASK; ! 1759: break; ! 1760: case VNC_ENCODING_POINTER_TYPE_CHANGE: ! 1761: vs->features |= VNC_FEATURE_POINTER_TYPE_CHANGE_MASK; ! 1762: break; ! 1763: case VNC_ENCODING_RICH_CURSOR: ! 1764: vs->features |= VNC_FEATURE_RICH_CURSOR_MASK; ! 1765: break; ! 1766: case VNC_ENCODING_EXT_KEY_EVENT: ! 1767: send_ext_key_event_ack(vs); ! 1768: break; ! 1769: case VNC_ENCODING_AUDIO: ! 1770: send_ext_audio_ack(vs); ! 1771: break; ! 1772: case VNC_ENCODING_WMVi: ! 1773: vs->features |= VNC_FEATURE_WMVI_MASK; ! 1774: break; ! 1775: case VNC_ENCODING_COMPRESSLEVEL0 ... VNC_ENCODING_COMPRESSLEVEL0 + 9: ! 1776: vs->tight.compression = (enc & 0x0F); ! 1777: break; ! 1778: case VNC_ENCODING_QUALITYLEVEL0 ... VNC_ENCODING_QUALITYLEVEL0 + 9: ! 1779: vs->tight.quality = (enc & 0x0F); ! 1780: break; ! 1781: default: ! 1782: VNC_DEBUG("Unknown encoding: %d (0x%.8x): %d\n", i, enc, enc); ! 1783: break; ! 1784: } ! 1785: } ! 1786: vnc_desktop_resize(vs); ! 1787: check_pointer_type_change(&vs->mouse_mode_notifier); ! 1788: } ! 1789: ! 1790: static void set_pixel_conversion(VncState *vs) ! 1791: { ! 1792: if ((vs->clientds.flags & QEMU_BIG_ENDIAN_FLAG) == ! 1793: (vs->ds->surface->flags & QEMU_BIG_ENDIAN_FLAG) && ! 1794: !memcmp(&(vs->clientds.pf), &(vs->ds->surface->pf), sizeof(PixelFormat))) { ! 1795: vs->write_pixels = vnc_write_pixels_copy; ! 1796: vnc_hextile_set_pixel_conversion(vs, 0); ! 1797: } else { ! 1798: vs->write_pixels = vnc_write_pixels_generic; ! 1799: vnc_hextile_set_pixel_conversion(vs, 1); ! 1800: } ! 1801: } ! 1802: ! 1803: static void set_pixel_format(VncState *vs, ! 1804: int bits_per_pixel, int depth, ! 1805: int big_endian_flag, int true_color_flag, ! 1806: int red_max, int green_max, int blue_max, ! 1807: int red_shift, int green_shift, int blue_shift) ! 1808: { ! 1809: if (!true_color_flag) { ! 1810: vnc_client_error(vs); ! 1811: return; ! 1812: } ! 1813: ! 1814: vs->clientds = *(vs->vd->guest.ds); ! 1815: vs->clientds.pf.rmax = red_max; ! 1816: count_bits(vs->clientds.pf.rbits, red_max); ! 1817: vs->clientds.pf.rshift = red_shift; ! 1818: vs->clientds.pf.rmask = red_max << red_shift; ! 1819: vs->clientds.pf.gmax = green_max; ! 1820: count_bits(vs->clientds.pf.gbits, green_max); ! 1821: vs->clientds.pf.gshift = green_shift; ! 1822: vs->clientds.pf.gmask = green_max << green_shift; ! 1823: vs->clientds.pf.bmax = blue_max; ! 1824: count_bits(vs->clientds.pf.bbits, blue_max); ! 1825: vs->clientds.pf.bshift = blue_shift; ! 1826: vs->clientds.pf.bmask = blue_max << blue_shift; ! 1827: vs->clientds.pf.bits_per_pixel = bits_per_pixel; ! 1828: vs->clientds.pf.bytes_per_pixel = bits_per_pixel / 8; ! 1829: vs->clientds.pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel; ! 1830: vs->clientds.flags = big_endian_flag ? QEMU_BIG_ENDIAN_FLAG : 0x00; ! 1831: ! 1832: set_pixel_conversion(vs); ! 1833: ! 1834: vga_hw_invalidate(); ! 1835: vga_hw_update(); ! 1836: } ! 1837: ! 1838: static void pixel_format_message (VncState *vs) { ! 1839: char pad[3] = { 0, 0, 0 }; ! 1840: ! 1841: vnc_write_u8(vs, vs->ds->surface->pf.bits_per_pixel); /* bits-per-pixel */ ! 1842: vnc_write_u8(vs, vs->ds->surface->pf.depth); /* depth */ ! 1843: ! 1844: #ifdef HOST_WORDS_BIGENDIAN ! 1845: vnc_write_u8(vs, 1); /* big-endian-flag */ ! 1846: #else ! 1847: vnc_write_u8(vs, 0); /* big-endian-flag */ ! 1848: #endif ! 1849: vnc_write_u8(vs, 1); /* true-color-flag */ ! 1850: vnc_write_u16(vs, vs->ds->surface->pf.rmax); /* red-max */ ! 1851: vnc_write_u16(vs, vs->ds->surface->pf.gmax); /* green-max */ ! 1852: vnc_write_u16(vs, vs->ds->surface->pf.bmax); /* blue-max */ ! 1853: vnc_write_u8(vs, vs->ds->surface->pf.rshift); /* red-shift */ ! 1854: vnc_write_u8(vs, vs->ds->surface->pf.gshift); /* green-shift */ ! 1855: vnc_write_u8(vs, vs->ds->surface->pf.bshift); /* blue-shift */ ! 1856: ! 1857: vnc_hextile_set_pixel_conversion(vs, 0); ! 1858: ! 1859: vs->clientds = *(vs->ds->surface); ! 1860: vs->clientds.flags &= ~QEMU_ALLOCATED_FLAG; ! 1861: vs->write_pixels = vnc_write_pixels_copy; ! 1862: ! 1863: vnc_write(vs, pad, 3); /* padding */ ! 1864: } ! 1865: ! 1866: static void vnc_dpy_setdata(DisplayState *ds) ! 1867: { ! 1868: /* We don't have to do anything */ ! 1869: } ! 1870: ! 1871: static void vnc_colordepth(VncState *vs) ! 1872: { ! 1873: if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) { ! 1874: /* Sending a WMVi message to notify the client*/ ! 1875: vnc_lock_output(vs); ! 1876: vnc_write_u8(vs, VNC_MSG_SERVER_FRAMEBUFFER_UPDATE); ! 1877: vnc_write_u8(vs, 0); ! 1878: vnc_write_u16(vs, 1); /* number of rects */ ! 1879: vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds), ! 1880: ds_get_height(vs->ds), VNC_ENCODING_WMVi); ! 1881: pixel_format_message(vs); ! 1882: vnc_unlock_output(vs); ! 1883: vnc_flush(vs); ! 1884: } else { ! 1885: set_pixel_conversion(vs); ! 1886: } ! 1887: } ! 1888: ! 1889: static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len) ! 1890: { ! 1891: int i; ! 1892: uint16_t limit; ! 1893: VncDisplay *vd = vs->vd; ! 1894: ! 1895: if (data[0] > 3) { ! 1896: vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; ! 1897: if (!qemu_timer_expired(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval)) ! 1898: qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval); ! 1899: } ! 1900: ! 1901: switch (data[0]) { ! 1902: case VNC_MSG_CLIENT_SET_PIXEL_FORMAT: ! 1903: if (len == 1) ! 1904: return 20; ! 1905: ! 1906: set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5), ! 1907: read_u8(data, 6), read_u8(data, 7), ! 1908: read_u16(data, 8), read_u16(data, 10), ! 1909: read_u16(data, 12), read_u8(data, 14), ! 1910: read_u8(data, 15), read_u8(data, 16)); ! 1911: break; ! 1912: case VNC_MSG_CLIENT_SET_ENCODINGS: ! 1913: if (len == 1) ! 1914: return 4; ! 1915: ! 1916: if (len == 4) { ! 1917: limit = read_u16(data, 2); ! 1918: if (limit > 0) ! 1919: return 4 + (limit * 4); ! 1920: } else ! 1921: limit = read_u16(data, 2); ! 1922: ! 1923: for (i = 0; i < limit; i++) { ! 1924: int32_t val = read_s32(data, 4 + (i * 4)); ! 1925: memcpy(data + 4 + (i * 4), &val, sizeof(val)); ! 1926: } ! 1927: ! 1928: set_encodings(vs, (int32_t *)(data + 4), limit); ! 1929: break; ! 1930: case VNC_MSG_CLIENT_FRAMEBUFFER_UPDATE_REQUEST: ! 1931: if (len == 1) ! 1932: return 10; ! 1933: ! 1934: framebuffer_update_request(vs, ! 1935: read_u8(data, 1), read_u16(data, 2), read_u16(data, 4), ! 1936: read_u16(data, 6), read_u16(data, 8)); ! 1937: break; ! 1938: case VNC_MSG_CLIENT_KEY_EVENT: ! 1939: if (len == 1) ! 1940: return 8; ! 1941: ! 1942: key_event(vs, read_u8(data, 1), read_u32(data, 4)); ! 1943: break; ! 1944: case VNC_MSG_CLIENT_POINTER_EVENT: ! 1945: if (len == 1) ! 1946: return 6; ! 1947: ! 1948: pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); ! 1949: break; ! 1950: case VNC_MSG_CLIENT_CUT_TEXT: ! 1951: if (len == 1) ! 1952: return 8; ! 1953: ! 1954: if (len == 8) { ! 1955: uint32_t dlen = read_u32(data, 4); ! 1956: if (dlen > 0) ! 1957: return 8 + dlen; ! 1958: } ! 1959: ! 1960: client_cut_text(vs, read_u32(data, 4), data + 8); ! 1961: break; ! 1962: case VNC_MSG_CLIENT_QEMU: ! 1963: if (len == 1) ! 1964: return 2; ! 1965: ! 1966: switch (read_u8(data, 1)) { ! 1967: case VNC_MSG_CLIENT_QEMU_EXT_KEY_EVENT: ! 1968: if (len == 2) ! 1969: return 12; ! 1970: ! 1971: ext_key_event(vs, read_u16(data, 2), ! 1972: read_u32(data, 4), read_u32(data, 8)); ! 1973: break; ! 1974: case VNC_MSG_CLIENT_QEMU_AUDIO: ! 1975: if (len == 2) ! 1976: return 4; ! 1977: ! 1978: switch (read_u16 (data, 2)) { ! 1979: case VNC_MSG_CLIENT_QEMU_AUDIO_ENABLE: ! 1980: audio_add(vs); ! 1981: break; ! 1982: case VNC_MSG_CLIENT_QEMU_AUDIO_DISABLE: ! 1983: audio_del(vs); ! 1984: break; ! 1985: case VNC_MSG_CLIENT_QEMU_AUDIO_SET_FORMAT: ! 1986: if (len == 4) ! 1987: return 10; ! 1988: switch (read_u8(data, 4)) { ! 1989: case 0: vs->as.fmt = AUD_FMT_U8; break; ! 1990: case 1: vs->as.fmt = AUD_FMT_S8; break; ! 1991: case 2: vs->as.fmt = AUD_FMT_U16; break; ! 1992: case 3: vs->as.fmt = AUD_FMT_S16; break; ! 1993: case 4: vs->as.fmt = AUD_FMT_U32; break; ! 1994: case 5: vs->as.fmt = AUD_FMT_S32; break; ! 1995: default: ! 1996: printf("Invalid audio format %d\n", read_u8(data, 4)); ! 1997: vnc_client_error(vs); ! 1998: break; ! 1999: } ! 2000: vs->as.nchannels = read_u8(data, 5); ! 2001: if (vs->as.nchannels != 1 && vs->as.nchannels != 2) { ! 2002: printf("Invalid audio channel coount %d\n", ! 2003: read_u8(data, 5)); ! 2004: vnc_client_error(vs); ! 2005: break; ! 2006: } ! 2007: vs->as.freq = read_u32(data, 6); ! 2008: break; ! 2009: default: ! 2010: printf ("Invalid audio message %d\n", read_u8(data, 4)); ! 2011: vnc_client_error(vs); ! 2012: break; ! 2013: } ! 2014: break; ! 2015: ! 2016: default: ! 2017: printf("Msg: %d\n", read_u16(data, 0)); ! 2018: vnc_client_error(vs); ! 2019: break; ! 2020: } ! 2021: break; ! 2022: default: ! 2023: printf("Msg: %d\n", data[0]); ! 2024: vnc_client_error(vs); ! 2025: break; ! 2026: } ! 2027: ! 2028: vnc_read_when(vs, protocol_client_msg, 1); ! 2029: return 0; ! 2030: } ! 2031: ! 2032: static int protocol_client_init(VncState *vs, uint8_t *data, size_t len) ! 2033: { ! 2034: char buf[1024]; ! 2035: int size; ! 2036: ! 2037: vs->client_width = ds_get_width(vs->ds); ! 2038: vs->client_height = ds_get_height(vs->ds); ! 2039: vnc_write_u16(vs, vs->client_width); ! 2040: vnc_write_u16(vs, vs->client_height); ! 2041: ! 2042: pixel_format_message(vs); ! 2043: ! 2044: if (qemu_name) ! 2045: size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name); ! 2046: else ! 2047: size = snprintf(buf, sizeof(buf), "QEMU"); ! 2048: ! 2049: vnc_write_u32(vs, size); ! 2050: vnc_write(vs, buf, size); ! 2051: vnc_flush(vs); ! 2052: ! 2053: vnc_client_cache_auth(vs); ! 2054: vnc_qmp_event(vs, QEVENT_VNC_INITIALIZED); ! 2055: ! 2056: vnc_read_when(vs, protocol_client_msg, 1); ! 2057: ! 2058: return 0; ! 2059: } ! 2060: ! 2061: void start_client_init(VncState *vs) ! 2062: { ! 2063: vnc_read_when(vs, protocol_client_init, 1); ! 2064: } ! 2065: ! 2066: static void make_challenge(VncState *vs) ! 2067: { ! 2068: int i; ! 2069: ! 2070: srand(time(NULL)+getpid()+getpid()*987654+rand()); ! 2071: ! 2072: for (i = 0 ; i < sizeof(vs->challenge) ; i++) ! 2073: vs->challenge[i] = (int) (256.0*rand()/(RAND_MAX+1.0)); ! 2074: } ! 2075: ! 2076: static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len) ! 2077: { ! 2078: unsigned char response[VNC_AUTH_CHALLENGE_SIZE]; ! 2079: int i, j, pwlen; ! 2080: unsigned char key[8]; ! 2081: ! 2082: if (!vs->vd->password || !vs->vd->password[0]) { ! 2083: VNC_DEBUG("No password configured on server"); ! 2084: vnc_write_u32(vs, 1); /* Reject auth */ ! 2085: if (vs->minor >= 8) { ! 2086: static const char err[] = "Authentication failed"; ! 2087: vnc_write_u32(vs, sizeof(err)); ! 2088: vnc_write(vs, err, sizeof(err)); ! 2089: } ! 2090: vnc_flush(vs); ! 2091: vnc_client_error(vs); ! 2092: return 0; ! 2093: } ! 2094: ! 2095: memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE); ! 2096: ! 2097: /* Calculate the expected challenge response */ ! 2098: pwlen = strlen(vs->vd->password); ! 2099: for (i=0; i<sizeof(key); i++) ! 2100: key[i] = i<pwlen ? vs->vd->password[i] : 0; ! 2101: deskey(key, EN0); ! 2102: for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8) ! 2103: des(response+j, response+j); ! 2104: ! 2105: /* Compare expected vs actual challenge response */ ! 2106: if (memcmp(response, data, VNC_AUTH_CHALLENGE_SIZE) != 0) { ! 2107: VNC_DEBUG("Client challenge reponse did not match\n"); ! 2108: vnc_write_u32(vs, 1); /* Reject auth */ ! 2109: if (vs->minor >= 8) { ! 2110: static const char err[] = "Authentication failed"; ! 2111: vnc_write_u32(vs, sizeof(err)); ! 2112: vnc_write(vs, err, sizeof(err)); ! 2113: } ! 2114: vnc_flush(vs); ! 2115: vnc_client_error(vs); ! 2116: } else { ! 2117: VNC_DEBUG("Accepting VNC challenge response\n"); ! 2118: vnc_write_u32(vs, 0); /* Accept auth */ ! 2119: vnc_flush(vs); ! 2120: ! 2121: start_client_init(vs); ! 2122: } ! 2123: return 0; ! 2124: } ! 2125: ! 2126: void start_auth_vnc(VncState *vs) ! 2127: { ! 2128: make_challenge(vs); ! 2129: /* Send client a 'random' challenge */ ! 2130: vnc_write(vs, vs->challenge, sizeof(vs->challenge)); ! 2131: vnc_flush(vs); ! 2132: ! 2133: vnc_read_when(vs, protocol_client_auth_vnc, sizeof(vs->challenge)); ! 2134: } ! 2135: ! 2136: ! 2137: static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len) ! 2138: { ! 2139: /* We only advertise 1 auth scheme at a time, so client ! 2140: * must pick the one we sent. Verify this */ ! 2141: if (data[0] != vs->vd->auth) { /* Reject auth */ ! 2142: VNC_DEBUG("Reject auth %d because it didn't match advertized\n", (int)data[0]); ! 2143: vnc_write_u32(vs, 1); ! 2144: if (vs->minor >= 8) { ! 2145: static const char err[] = "Authentication failed"; ! 2146: vnc_write_u32(vs, sizeof(err)); ! 2147: vnc_write(vs, err, sizeof(err)); ! 2148: } ! 2149: vnc_client_error(vs); ! 2150: } else { /* Accept requested auth */ ! 2151: VNC_DEBUG("Client requested auth %d\n", (int)data[0]); ! 2152: switch (vs->vd->auth) { ! 2153: case VNC_AUTH_NONE: ! 2154: VNC_DEBUG("Accept auth none\n"); ! 2155: if (vs->minor >= 8) { ! 2156: vnc_write_u32(vs, 0); /* Accept auth completion */ ! 2157: vnc_flush(vs); ! 2158: } ! 2159: start_client_init(vs); ! 2160: break; ! 2161: ! 2162: case VNC_AUTH_VNC: ! 2163: VNC_DEBUG("Start VNC auth\n"); ! 2164: start_auth_vnc(vs); ! 2165: break; ! 2166: ! 2167: #ifdef CONFIG_VNC_TLS ! 2168: case VNC_AUTH_VENCRYPT: ! 2169: VNC_DEBUG("Accept VeNCrypt auth\n");; ! 2170: start_auth_vencrypt(vs); ! 2171: break; ! 2172: #endif /* CONFIG_VNC_TLS */ ! 2173: ! 2174: #ifdef CONFIG_VNC_SASL ! 2175: case VNC_AUTH_SASL: ! 2176: VNC_DEBUG("Accept SASL auth\n"); ! 2177: start_auth_sasl(vs); ! 2178: break; ! 2179: #endif /* CONFIG_VNC_SASL */ ! 2180: ! 2181: default: /* Should not be possible, but just in case */ ! 2182: VNC_DEBUG("Reject auth %d server code bug\n", vs->vd->auth); ! 2183: vnc_write_u8(vs, 1); ! 2184: if (vs->minor >= 8) { ! 2185: static const char err[] = "Authentication failed"; ! 2186: vnc_write_u32(vs, sizeof(err)); ! 2187: vnc_write(vs, err, sizeof(err)); ! 2188: } ! 2189: vnc_client_error(vs); ! 2190: } ! 2191: } ! 2192: return 0; ! 2193: } ! 2194: ! 2195: static int protocol_version(VncState *vs, uint8_t *version, size_t len) ! 2196: { ! 2197: char local[13]; ! 2198: ! 2199: memcpy(local, version, 12); ! 2200: local[12] = 0; ! 2201: ! 2202: if (sscanf(local, "RFB %03d.%03d\n", &vs->major, &vs->minor) != 2) { ! 2203: VNC_DEBUG("Malformed protocol version %s\n", local); ! 2204: vnc_client_error(vs); ! 2205: return 0; ! 2206: } ! 2207: VNC_DEBUG("Client request protocol version %d.%d\n", vs->major, vs->minor); ! 2208: if (vs->major != 3 || ! 2209: (vs->minor != 3 && ! 2210: vs->minor != 4 && ! 2211: vs->minor != 5 && ! 2212: vs->minor != 7 && ! 2213: vs->minor != 8)) { ! 2214: VNC_DEBUG("Unsupported client version\n"); ! 2215: vnc_write_u32(vs, VNC_AUTH_INVALID); ! 2216: vnc_flush(vs); ! 2217: vnc_client_error(vs); ! 2218: return 0; ! 2219: } ! 2220: /* Some broken clients report v3.4 or v3.5, which spec requires to be treated ! 2221: * as equivalent to v3.3 by servers ! 2222: */ ! 2223: if (vs->minor == 4 || vs->minor == 5) ! 2224: vs->minor = 3; ! 2225: ! 2226: if (vs->minor == 3) { ! 2227: if (vs->vd->auth == VNC_AUTH_NONE) { ! 2228: VNC_DEBUG("Tell client auth none\n"); ! 2229: vnc_write_u32(vs, vs->vd->auth); ! 2230: vnc_flush(vs); ! 2231: start_client_init(vs); ! 2232: } else if (vs->vd->auth == VNC_AUTH_VNC) { ! 2233: VNC_DEBUG("Tell client VNC auth\n"); ! 2234: vnc_write_u32(vs, vs->vd->auth); ! 2235: vnc_flush(vs); ! 2236: start_auth_vnc(vs); ! 2237: } else { ! 2238: VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth); ! 2239: vnc_write_u32(vs, VNC_AUTH_INVALID); ! 2240: vnc_flush(vs); ! 2241: vnc_client_error(vs); ! 2242: } ! 2243: } else { ! 2244: VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth); ! 2245: vnc_write_u8(vs, 1); /* num auth */ ! 2246: vnc_write_u8(vs, vs->vd->auth); ! 2247: vnc_read_when(vs, protocol_client_auth, 1); ! 2248: vnc_flush(vs); ! 2249: } ! 2250: ! 2251: return 0; ! 2252: } ! 2253: ! 2254: static int vnc_refresh_server_surface(VncDisplay *vd) ! 2255: { ! 2256: int y; ! 2257: uint8_t *guest_row; ! 2258: uint8_t *server_row; ! 2259: int cmp_bytes; ! 2260: uint32_t width_mask[VNC_DIRTY_WORDS]; ! 2261: VncState *vs; ! 2262: int has_dirty = 0; ! 2263: ! 2264: /* ! 2265: * Walk through the guest dirty map. ! 2266: * Check and copy modified bits from guest to server surface. ! 2267: * Update server dirty map. ! 2268: */ ! 2269: vnc_set_bits(width_mask, (ds_get_width(vd->ds) / 16), VNC_DIRTY_WORDS); ! 2270: cmp_bytes = 16 * ds_get_bytes_per_pixel(vd->ds); ! 2271: guest_row = vd->guest.ds->data; ! 2272: server_row = vd->server->data; ! 2273: for (y = 0; y < vd->guest.ds->height; y++) { ! 2274: if (vnc_and_bits(vd->guest.dirty[y], width_mask, VNC_DIRTY_WORDS)) { ! 2275: int x; ! 2276: uint8_t *guest_ptr; ! 2277: uint8_t *server_ptr; ! 2278: ! 2279: guest_ptr = guest_row; ! 2280: server_ptr = server_row; ! 2281: ! 2282: for (x = 0; x < vd->guest.ds->width; ! 2283: x += 16, guest_ptr += cmp_bytes, server_ptr += cmp_bytes) { ! 2284: if (!vnc_get_bit(vd->guest.dirty[y], (x / 16))) ! 2285: continue; ! 2286: vnc_clear_bit(vd->guest.dirty[y], (x / 16)); ! 2287: if (memcmp(server_ptr, guest_ptr, cmp_bytes) == 0) ! 2288: continue; ! 2289: memcpy(server_ptr, guest_ptr, cmp_bytes); ! 2290: QTAILQ_FOREACH(vs, &vd->clients, next) { ! 2291: vnc_set_bit(vs->dirty[y], (x / 16)); ! 2292: } ! 2293: has_dirty++; ! 2294: } ! 2295: } ! 2296: guest_row += ds_get_linesize(vd->ds); ! 2297: server_row += ds_get_linesize(vd->ds); ! 2298: } ! 2299: return has_dirty; ! 2300: } ! 2301: ! 2302: static void vnc_refresh(void *opaque) ! 2303: { ! 2304: VncDisplay *vd = opaque; ! 2305: VncState *vs, *vn; ! 2306: int has_dirty, rects = 0; ! 2307: ! 2308: vga_hw_update(); ! 2309: ! 2310: if (vnc_trylock_display(vd)) { ! 2311: vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; ! 2312: qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + ! 2313: vd->timer_interval); ! 2314: return; ! 2315: } ! 2316: ! 2317: has_dirty = vnc_refresh_server_surface(vd); ! 2318: vnc_unlock_display(vd); ! 2319: ! 2320: QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) { ! 2321: rects += vnc_update_client(vs, has_dirty); ! 2322: /* vs might be free()ed here */ ! 2323: } ! 2324: ! 2325: /* vd->timer could be NULL now if the last client disconnected, ! 2326: * in this case don't update the timer */ ! 2327: if (vd->timer == NULL) ! 2328: return; ! 2329: ! 2330: if (has_dirty && rects) { ! 2331: vd->timer_interval /= 2; ! 2332: if (vd->timer_interval < VNC_REFRESH_INTERVAL_BASE) ! 2333: vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; ! 2334: } else { ! 2335: vd->timer_interval += VNC_REFRESH_INTERVAL_INC; ! 2336: if (vd->timer_interval > VNC_REFRESH_INTERVAL_MAX) ! 2337: vd->timer_interval = VNC_REFRESH_INTERVAL_MAX; ! 2338: } ! 2339: qemu_mod_timer(vd->timer, qemu_get_clock(rt_clock) + vd->timer_interval); ! 2340: } ! 2341: ! 2342: static void vnc_init_timer(VncDisplay *vd) ! 2343: { ! 2344: vd->timer_interval = VNC_REFRESH_INTERVAL_BASE; ! 2345: if (vd->timer == NULL && !QTAILQ_EMPTY(&vd->clients)) { ! 2346: vd->timer = qemu_new_timer(rt_clock, vnc_refresh, vd); ! 2347: vnc_refresh(vd); ! 2348: } ! 2349: } ! 2350: ! 2351: static void vnc_remove_timer(VncDisplay *vd) ! 2352: { ! 2353: if (vd->timer != NULL && QTAILQ_EMPTY(&vd->clients)) { ! 2354: qemu_del_timer(vd->timer); ! 2355: qemu_free_timer(vd->timer); ! 2356: vd->timer = NULL; ! 2357: } ! 2358: } ! 2359: ! 2360: static void vnc_connect(VncDisplay *vd, int csock) ! 2361: { ! 2362: VncState *vs = qemu_mallocz(sizeof(VncState)); ! 2363: vs->csock = csock; ! 2364: ! 2365: VNC_DEBUG("New client on socket %d\n", csock); ! 2366: dcl->idle = 0; ! 2367: socket_set_nonblock(vs->csock); ! 2368: qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); ! 2369: ! 2370: vnc_client_cache_addr(vs); ! 2371: vnc_qmp_event(vs, QEVENT_VNC_CONNECTED); ! 2372: ! 2373: vs->vd = vd; ! 2374: vs->ds = vd->ds; ! 2375: vs->last_x = -1; ! 2376: vs->last_y = -1; ! 2377: ! 2378: vs->as.freq = 44100; ! 2379: vs->as.nchannels = 2; ! 2380: vs->as.fmt = AUD_FMT_S16; ! 2381: vs->as.endianness = 0; ! 2382: ! 2383: #ifdef CONFIG_VNC_THREAD ! 2384: qemu_mutex_init(&vs->output_mutex); ! 2385: #endif ! 2386: ! 2387: QTAILQ_INSERT_HEAD(&vd->clients, vs, next); ! 2388: ! 2389: vga_hw_update(); ! 2390: ! 2391: vnc_write(vs, "RFB 003.008\n", 12); ! 2392: vnc_flush(vs); ! 2393: vnc_read_when(vs, protocol_version, 12); ! 2394: reset_keys(vs); ! 2395: if (vs->vd->lock_key_sync) ! 2396: vs->led = qemu_add_led_event_handler(kbd_leds, vs); ! 2397: ! 2398: vs->mouse_mode_notifier.notify = check_pointer_type_change; ! 2399: qemu_add_mouse_mode_change_notifier(&vs->mouse_mode_notifier); ! 2400: ! 2401: vnc_init_timer(vd); ! 2402: ! 2403: /* vs might be free()ed here */ ! 2404: } ! 2405: ! 2406: static void vnc_listen_read(void *opaque) ! 2407: { ! 2408: VncDisplay *vs = opaque; ! 2409: struct sockaddr_in addr; ! 2410: socklen_t addrlen = sizeof(addr); ! 2411: ! 2412: /* Catch-up */ ! 2413: vga_hw_update(); ! 2414: ! 2415: int csock = qemu_accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); ! 2416: if (csock != -1) { ! 2417: vnc_connect(vs, csock); ! 2418: } ! 2419: } ! 2420: ! 2421: void vnc_display_init(DisplayState *ds) ! 2422: { ! 2423: VncDisplay *vs = qemu_mallocz(sizeof(*vs)); ! 2424: ! 2425: dcl = qemu_mallocz(sizeof(DisplayChangeListener)); ! 2426: ! 2427: ds->opaque = vs; ! 2428: dcl->idle = 1; ! 2429: vnc_display = vs; ! 2430: ! 2431: vs->lsock = -1; ! 2432: ! 2433: vs->ds = ds; ! 2434: QTAILQ_INIT(&vs->clients); ! 2435: ! 2436: if (keyboard_layout) ! 2437: vs->kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout); ! 2438: else ! 2439: vs->kbd_layout = init_keyboard_layout(name2keysym, "en-us"); ! 2440: ! 2441: if (!vs->kbd_layout) ! 2442: exit(1); ! 2443: ! 2444: #ifdef CONFIG_VNC_THREAD ! 2445: qemu_mutex_init(&vs->mutex); ! 2446: vnc_start_worker_thread(); ! 2447: #endif ! 2448: ! 2449: dcl->dpy_copy = vnc_dpy_copy; ! 2450: dcl->dpy_update = vnc_dpy_update; ! 2451: dcl->dpy_resize = vnc_dpy_resize; ! 2452: dcl->dpy_setdata = vnc_dpy_setdata; ! 2453: register_displaychangelistener(ds, dcl); ! 2454: ds->mouse_set = vnc_mouse_set; ! 2455: ds->cursor_define = vnc_dpy_cursor_define; ! 2456: } ! 2457: ! 2458: ! 2459: void vnc_display_close(DisplayState *ds) ! 2460: { ! 2461: VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; ! 2462: ! 2463: if (!vs) ! 2464: return; ! 2465: if (vs->display) { ! 2466: qemu_free(vs->display); ! 2467: vs->display = NULL; ! 2468: } ! 2469: if (vs->lsock != -1) { ! 2470: qemu_set_fd_handler2(vs->lsock, NULL, NULL, NULL, NULL); ! 2471: close(vs->lsock); ! 2472: vs->lsock = -1; ! 2473: } ! 2474: vs->auth = VNC_AUTH_INVALID; ! 2475: #ifdef CONFIG_VNC_TLS ! 2476: vs->subauth = VNC_AUTH_INVALID; ! 2477: vs->tls.x509verify = 0; ! 2478: #endif ! 2479: } ! 2480: ! 2481: int vnc_display_password(DisplayState *ds, const char *password) ! 2482: { ! 2483: VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; ! 2484: ! 2485: if (!vs) { ! 2486: return -1; ! 2487: } ! 2488: ! 2489: if (vs->password) { ! 2490: qemu_free(vs->password); ! 2491: vs->password = NULL; ! 2492: } ! 2493: if (password && password[0]) { ! 2494: if (!(vs->password = qemu_strdup(password))) ! 2495: return -1; ! 2496: if (vs->auth == VNC_AUTH_NONE) { ! 2497: vs->auth = VNC_AUTH_VNC; ! 2498: } ! 2499: } else { ! 2500: vs->auth = VNC_AUTH_NONE; ! 2501: } ! 2502: ! 2503: return 0; ! 2504: } ! 2505: ! 2506: char *vnc_display_local_addr(DisplayState *ds) ! 2507: { ! 2508: VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; ! 2509: ! 2510: return vnc_socket_local_addr("%s:%s", vs->lsock); ! 2511: } ! 2512: ! 2513: int vnc_display_open(DisplayState *ds, const char *display) ! 2514: { ! 2515: VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display; ! 2516: const char *options; ! 2517: int password = 0; ! 2518: int reverse = 0; ! 2519: #ifdef CONFIG_VNC_TLS ! 2520: int tls = 0, x509 = 0; ! 2521: #endif ! 2522: #ifdef CONFIG_VNC_SASL ! 2523: int sasl = 0; ! 2524: int saslErr; ! 2525: #endif ! 2526: int acl = 0; ! 2527: int lock_key_sync = 1; ! 2528: ! 2529: if (!vnc_display) ! 2530: return -1; ! 2531: vnc_display_close(ds); ! 2532: if (strcmp(display, "none") == 0) ! 2533: return 0; ! 2534: ! 2535: if (!(vs->display = strdup(display))) ! 2536: return -1; ! 2537: ! 2538: options = display; ! 2539: while ((options = strchr(options, ','))) { ! 2540: options++; ! 2541: if (strncmp(options, "password", 8) == 0) { ! 2542: password = 1; /* Require password auth */ ! 2543: } else if (strncmp(options, "reverse", 7) == 0) { ! 2544: reverse = 1; ! 2545: } else if (strncmp(options, "no-lock-key-sync", 9) == 0) { ! 2546: lock_key_sync = 0; ! 2547: #ifdef CONFIG_VNC_SASL ! 2548: } else if (strncmp(options, "sasl", 4) == 0) { ! 2549: sasl = 1; /* Require SASL auth */ ! 2550: #endif ! 2551: #ifdef CONFIG_VNC_TLS ! 2552: } else if (strncmp(options, "tls", 3) == 0) { ! 2553: tls = 1; /* Require TLS */ ! 2554: } else if (strncmp(options, "x509", 4) == 0) { ! 2555: char *start, *end; ! 2556: x509 = 1; /* Require x509 certificates */ ! 2557: if (strncmp(options, "x509verify", 10) == 0) ! 2558: vs->tls.x509verify = 1; /* ...and verify client certs */ ! 2559: ! 2560: /* Now check for 'x509=/some/path' postfix ! 2561: * and use that to setup x509 certificate/key paths */ ! 2562: start = strchr(options, '='); ! 2563: end = strchr(options, ','); ! 2564: if (start && (!end || (start < end))) { ! 2565: int len = end ? end-(start+1) : strlen(start+1); ! 2566: char *path = qemu_strndup(start + 1, len); ! 2567: ! 2568: VNC_DEBUG("Trying certificate path '%s'\n", path); ! 2569: if (vnc_tls_set_x509_creds_dir(vs, path) < 0) { ! 2570: fprintf(stderr, "Failed to find x509 certificates/keys in %s\n", path); ! 2571: qemu_free(path); ! 2572: qemu_free(vs->display); ! 2573: vs->display = NULL; ! 2574: return -1; ! 2575: } ! 2576: qemu_free(path); ! 2577: } else { ! 2578: fprintf(stderr, "No certificate path provided\n"); ! 2579: qemu_free(vs->display); ! 2580: vs->display = NULL; ! 2581: return -1; ! 2582: } ! 2583: #endif ! 2584: } else if (strncmp(options, "acl", 3) == 0) { ! 2585: acl = 1; ! 2586: } else if (strncmp(options, "lossy", 5) == 0) { ! 2587: vs->lossy = true; ! 2588: } ! 2589: } ! 2590: ! 2591: #ifdef CONFIG_VNC_TLS ! 2592: if (acl && x509 && vs->tls.x509verify) { ! 2593: if (!(vs->tls.acl = qemu_acl_init("vnc.x509dname"))) { ! 2594: fprintf(stderr, "Failed to create x509 dname ACL\n"); ! 2595: exit(1); ! 2596: } ! 2597: } ! 2598: #endif ! 2599: #ifdef CONFIG_VNC_SASL ! 2600: if (acl && sasl) { ! 2601: if (!(vs->sasl.acl = qemu_acl_init("vnc.username"))) { ! 2602: fprintf(stderr, "Failed to create username ACL\n"); ! 2603: exit(1); ! 2604: } ! 2605: } ! 2606: #endif ! 2607: ! 2608: /* ! 2609: * Combinations we support here: ! 2610: * ! 2611: * - no-auth (clear text, no auth) ! 2612: * - password (clear text, weak auth) ! 2613: * - sasl (encrypt, good auth *IF* using Kerberos via GSSAPI) ! 2614: * - tls (encrypt, weak anonymous creds, no auth) ! 2615: * - tls + password (encrypt, weak anonymous creds, weak auth) ! 2616: * - tls + sasl (encrypt, weak anonymous creds, good auth) ! 2617: * - tls + x509 (encrypt, good x509 creds, no auth) ! 2618: * - tls + x509 + password (encrypt, good x509 creds, weak auth) ! 2619: * - tls + x509 + sasl (encrypt, good x509 creds, good auth) ! 2620: * ! 2621: * NB1. TLS is a stackable auth scheme. ! 2622: * NB2. the x509 schemes have option to validate a client cert dname ! 2623: */ ! 2624: if (password) { ! 2625: #ifdef CONFIG_VNC_TLS ! 2626: if (tls) { ! 2627: vs->auth = VNC_AUTH_VENCRYPT; ! 2628: if (x509) { ! 2629: VNC_DEBUG("Initializing VNC server with x509 password auth\n"); ! 2630: vs->subauth = VNC_AUTH_VENCRYPT_X509VNC; ! 2631: } else { ! 2632: VNC_DEBUG("Initializing VNC server with TLS password auth\n"); ! 2633: vs->subauth = VNC_AUTH_VENCRYPT_TLSVNC; ! 2634: } ! 2635: } else { ! 2636: #endif /* CONFIG_VNC_TLS */ ! 2637: VNC_DEBUG("Initializing VNC server with password auth\n"); ! 2638: vs->auth = VNC_AUTH_VNC; ! 2639: #ifdef CONFIG_VNC_TLS ! 2640: vs->subauth = VNC_AUTH_INVALID; ! 2641: } ! 2642: #endif /* CONFIG_VNC_TLS */ ! 2643: #ifdef CONFIG_VNC_SASL ! 2644: } else if (sasl) { ! 2645: #ifdef CONFIG_VNC_TLS ! 2646: if (tls) { ! 2647: vs->auth = VNC_AUTH_VENCRYPT; ! 2648: if (x509) { ! 2649: VNC_DEBUG("Initializing VNC server with x509 SASL auth\n"); ! 2650: vs->subauth = VNC_AUTH_VENCRYPT_X509SASL; ! 2651: } else { ! 2652: VNC_DEBUG("Initializing VNC server with TLS SASL auth\n"); ! 2653: vs->subauth = VNC_AUTH_VENCRYPT_TLSSASL; ! 2654: } ! 2655: } else { ! 2656: #endif /* CONFIG_VNC_TLS */ ! 2657: VNC_DEBUG("Initializing VNC server with SASL auth\n"); ! 2658: vs->auth = VNC_AUTH_SASL; ! 2659: #ifdef CONFIG_VNC_TLS ! 2660: vs->subauth = VNC_AUTH_INVALID; ! 2661: } ! 2662: #endif /* CONFIG_VNC_TLS */ ! 2663: #endif /* CONFIG_VNC_SASL */ ! 2664: } else { ! 2665: #ifdef CONFIG_VNC_TLS ! 2666: if (tls) { ! 2667: vs->auth = VNC_AUTH_VENCRYPT; ! 2668: if (x509) { ! 2669: VNC_DEBUG("Initializing VNC server with x509 no auth\n"); ! 2670: vs->subauth = VNC_AUTH_VENCRYPT_X509NONE; ! 2671: } else { ! 2672: VNC_DEBUG("Initializing VNC server with TLS no auth\n"); ! 2673: vs->subauth = VNC_AUTH_VENCRYPT_TLSNONE; ! 2674: } ! 2675: } else { ! 2676: #endif ! 2677: VNC_DEBUG("Initializing VNC server with no auth\n"); ! 2678: vs->auth = VNC_AUTH_NONE; ! 2679: #ifdef CONFIG_VNC_TLS ! 2680: vs->subauth = VNC_AUTH_INVALID; ! 2681: } ! 2682: #endif ! 2683: } ! 2684: ! 2685: #ifdef CONFIG_VNC_SASL ! 2686: if ((saslErr = sasl_server_init(NULL, "qemu")) != SASL_OK) { ! 2687: fprintf(stderr, "Failed to initialize SASL auth %s", ! 2688: sasl_errstring(saslErr, NULL, NULL)); ! 2689: free(vs->display); ! 2690: vs->display = NULL; ! 2691: return -1; ! 2692: } ! 2693: #endif ! 2694: vs->lock_key_sync = lock_key_sync; ! 2695: ! 2696: if (reverse) { ! 2697: /* connect to viewer */ ! 2698: if (strncmp(display, "unix:", 5) == 0) ! 2699: vs->lsock = unix_connect(display+5); ! 2700: else ! 2701: vs->lsock = inet_connect(display, SOCK_STREAM); ! 2702: if (-1 == vs->lsock) { ! 2703: free(vs->display); ! 2704: vs->display = NULL; ! 2705: return -1; ! 2706: } else { ! 2707: int csock = vs->lsock; ! 2708: vs->lsock = -1; ! 2709: vnc_connect(vs, csock); ! 2710: } ! 2711: return 0; ! 2712: ! 2713: } else { ! 2714: /* listen for connects */ ! 2715: char *dpy; ! 2716: dpy = qemu_malloc(256); ! 2717: if (strncmp(display, "unix:", 5) == 0) { ! 2718: pstrcpy(dpy, 256, "unix:"); ! 2719: vs->lsock = unix_listen(display+5, dpy+5, 256-5); ! 2720: } else { ! 2721: vs->lsock = inet_listen(display, dpy, 256, SOCK_STREAM, 5900); ! 2722: } ! 2723: if (-1 == vs->lsock) { ! 2724: free(dpy); ! 2725: return -1; ! 2726: } else { ! 2727: free(vs->display); ! 2728: vs->display = dpy; ! 2729: } ! 2730: } ! 2731: return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs); ! 2732: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.