mirror of https://github.com/xemu-project/xemu.git
Support multiple VNC clients (Brian Kress)
Change structure associated with a display from VncState to a new structure VncDisplay. Remove client specific fields from VncDisplay. Remove display specific fields from VncState. Maintain a linked list of VncStates per VncDisplay structure, update as necessary. When updates/resizes/copies come in from the hardware, dispatch to all clients. Signed-off-by: Brian Kress <kressb@moose.net> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6621 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
880fec5d08
commit
753b405331
305
vnc.c
305
vnc.c
|
@ -90,12 +90,35 @@ typedef void VncSendHextileTile(VncState *vs,
|
|||
|
||||
#define VNC_AUTH_CHALLENGE_SIZE 16
|
||||
|
||||
typedef struct VncDisplay VncDisplay;
|
||||
|
||||
struct VncDisplay
|
||||
{
|
||||
int lsock;
|
||||
DisplayState *ds;
|
||||
VncState *clients;
|
||||
kbd_layout_t *kbd_layout;
|
||||
|
||||
char *display;
|
||||
char *password;
|
||||
int auth;
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
int subauth;
|
||||
int x509verify;
|
||||
|
||||
char *x509cacert;
|
||||
char *x509cacrl;
|
||||
char *x509cert;
|
||||
char *x509key;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct VncState
|
||||
{
|
||||
QEMUTimer *timer;
|
||||
int lsock;
|
||||
int csock;
|
||||
DisplayState *ds;
|
||||
VncDisplay *vd;
|
||||
int need_update;
|
||||
uint32_t dirty_row[VNC_MAX_HEIGHT][VNC_DIRTY_WORDS];
|
||||
char *old_data;
|
||||
|
@ -111,18 +134,6 @@ struct VncState
|
|||
int major;
|
||||
int minor;
|
||||
|
||||
char *display;
|
||||
char *password;
|
||||
int auth;
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
int subauth;
|
||||
int x509verify;
|
||||
|
||||
char *x509cacert;
|
||||
char *x509cacrl;
|
||||
char *x509cert;
|
||||
char *x509key;
|
||||
#endif
|
||||
char challenge[VNC_AUTH_CHALLENGE_SIZE];
|
||||
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
|
@ -132,7 +143,6 @@ struct VncState
|
|||
|
||||
Buffer output;
|
||||
Buffer input;
|
||||
kbd_layout_t *kbd_layout;
|
||||
/* current output mode information */
|
||||
VncWritePixels *write_pixels;
|
||||
VncSendHextileTile *send_hextile_tile;
|
||||
|
@ -149,21 +159,23 @@ struct VncState
|
|||
Buffer zlib;
|
||||
Buffer zlib_tmp;
|
||||
z_stream zlib_stream[4];
|
||||
|
||||
VncState *next;
|
||||
};
|
||||
|
||||
static VncState *vnc_state; /* needed for info vnc */
|
||||
static VncDisplay *vnc_display; /* needed for info vnc */
|
||||
static DisplayChangeListener *dcl;
|
||||
|
||||
void do_info_vnc(void)
|
||||
{
|
||||
if (vnc_state == NULL || vnc_state->display == NULL)
|
||||
if (vnc_display == NULL || vnc_display->display == NULL)
|
||||
term_printf("VNC server disabled\n");
|
||||
else {
|
||||
term_printf("VNC server active on: ");
|
||||
term_print_filename(vnc_state->display);
|
||||
term_print_filename(vnc_display->display);
|
||||
term_printf("\n");
|
||||
|
||||
if (vnc_state->csock == -1)
|
||||
if (vnc_display->clients == NULL)
|
||||
term_printf("No client connected\n");
|
||||
else
|
||||
term_printf("Client connected\n");
|
||||
|
@ -190,7 +202,7 @@ static void vnc_flush(VncState *vs);
|
|||
static void vnc_update_client(void *opaque);
|
||||
static void vnc_client_read(void *opaque);
|
||||
|
||||
static void vnc_colordepth(DisplayState *ds);
|
||||
static void vnc_colordepth(VncState *vs);
|
||||
|
||||
static inline void vnc_set_bit(uint32_t *d, int k)
|
||||
{
|
||||
|
@ -233,9 +245,8 @@ static inline int vnc_and_bits(const uint32_t *d1, const uint32_t *d2,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
|
||||
static void vnc_update(VncState *vs, int x, int y, int w, int h)
|
||||
{
|
||||
VncState *vs = ds->opaque;
|
||||
int i;
|
||||
|
||||
h += y;
|
||||
|
@ -257,6 +268,16 @@ static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
|
|||
vnc_set_bit(vs->dirty_row[y], (x + i) / 16);
|
||||
}
|
||||
|
||||
static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h)
|
||||
{
|
||||
VncDisplay *vd = ds->opaque;
|
||||
VncState *vs = vd->clients;
|
||||
while (vs != NULL) {
|
||||
vnc_update(vs, x, y, w, h);
|
||||
vs = vs->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
|
||||
int32_t encoding)
|
||||
{
|
||||
|
@ -301,10 +322,11 @@ static void buffer_append(Buffer *buffer, const void *data, size_t len)
|
|||
buffer->offset += len;
|
||||
}
|
||||
|
||||
static void vnc_dpy_resize(DisplayState *ds)
|
||||
static void vnc_resize(VncState *vs)
|
||||
{
|
||||
DisplayState *ds = vs->ds;
|
||||
|
||||
int size_changed;
|
||||
VncState *vs = ds->opaque;
|
||||
|
||||
vs->old_data = qemu_realloc(vs->old_data, ds_get_linesize(ds) * ds_get_height(ds));
|
||||
|
||||
|
@ -315,7 +337,7 @@ static void vnc_dpy_resize(DisplayState *ds)
|
|||
|
||||
if (ds_get_bytes_per_pixel(ds) != vs->serverds.pf.bytes_per_pixel)
|
||||
console_color_init(ds);
|
||||
vnc_colordepth(ds);
|
||||
vnc_colordepth(vs);
|
||||
size_changed = ds_get_width(ds) != vs->serverds.width ||
|
||||
ds_get_height(ds) != vs->serverds.height;
|
||||
vs->serverds = *(ds->surface);
|
||||
|
@ -334,6 +356,16 @@ static void vnc_dpy_resize(DisplayState *ds)
|
|||
memset(vs->old_data, 42, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
|
||||
}
|
||||
|
||||
static void vnc_dpy_resize(DisplayState *ds)
|
||||
{
|
||||
VncDisplay *vd = ds->opaque;
|
||||
VncState *vs = vd->clients;
|
||||
while (vs != NULL) {
|
||||
vnc_resize(vs);
|
||||
vs = vs->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* fastest code */
|
||||
static void vnc_write_pixels_copy(VncState *vs, void *pixels, int size)
|
||||
{
|
||||
|
@ -599,10 +631,8 @@ static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h)
|
|||
}
|
||||
}
|
||||
|
||||
static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
|
||||
static void vnc_copy(VncState *vs, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
|
||||
{
|
||||
VncState *vs = ds->opaque;
|
||||
|
||||
vnc_update_client(vs);
|
||||
|
||||
vnc_write_u8(vs, 0); /* msg id */
|
||||
|
@ -614,6 +644,19 @@ static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_
|
|||
vnc_flush(vs);
|
||||
}
|
||||
|
||||
static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h)
|
||||
{
|
||||
VncDisplay *vd = ds->opaque;
|
||||
VncState *vs = vd->clients;
|
||||
while (vs != NULL) {
|
||||
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT))
|
||||
vnc_copy(vs, src_x, src_y, dst_x, dst_y, w, h);
|
||||
else /* TODO */
|
||||
vnc_update(vs, dst_x, dst_y, w, h);
|
||||
vs = vs->next;
|
||||
}
|
||||
}
|
||||
|
||||
static int find_dirty_height(VncState *vs, int y, int last_x, int x)
|
||||
{
|
||||
int h;
|
||||
|
@ -632,7 +675,6 @@ static int find_dirty_height(VncState *vs, int y, int last_x, int x)
|
|||
static void vnc_update_client(void *opaque)
|
||||
{
|
||||
VncState *vs = opaque;
|
||||
|
||||
if (vs->need_update && vs->csock != -1) {
|
||||
int y;
|
||||
uint8_t *row;
|
||||
|
@ -725,14 +767,6 @@ static void vnc_update_client(void *opaque)
|
|||
|
||||
}
|
||||
|
||||
static int vnc_listen_poll(void *opaque)
|
||||
{
|
||||
VncState *vs = opaque;
|
||||
if (vs->csock == -1)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* audio */
|
||||
static void audio_capture_notify(void *opaque, audcnotification_e cmd)
|
||||
{
|
||||
|
@ -817,19 +851,35 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
|
|||
VNC_DEBUG("Closing down client sock %d %d\n", ret, ret < 0 ? last_errno : 0);
|
||||
qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
|
||||
closesocket(vs->csock);
|
||||
vs->csock = -1;
|
||||
dcl->idle = 1;
|
||||
buffer_reset(&vs->input);
|
||||
buffer_reset(&vs->output);
|
||||
vs->need_update = 0;
|
||||
qemu_del_timer(vs->timer);
|
||||
qemu_free_timer(vs->timer);
|
||||
if (vs->input.buffer) qemu_free(vs->input.buffer);
|
||||
if (vs->output.buffer) qemu_free(vs->output.buffer);
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
if (vs->tls_session) {
|
||||
gnutls_deinit(vs->tls_session);
|
||||
vs->tls_session = NULL;
|
||||
}
|
||||
vs->wiremode = VNC_WIREMODE_CLEAR;
|
||||
#endif /* CONFIG_VNC_TLS */
|
||||
audio_del(vs);
|
||||
|
||||
VncState *p, *parent = NULL;
|
||||
for (p = vs->vd->clients; p != NULL; p = p->next) {
|
||||
if (p == vs) {
|
||||
if (parent)
|
||||
parent->next = p->next;
|
||||
else
|
||||
vs->vd->clients = p->next;
|
||||
break;
|
||||
}
|
||||
parent = p;
|
||||
}
|
||||
if (!vs->vd->clients)
|
||||
dcl->idle = 1;
|
||||
|
||||
qemu_free(vs->old_data);
|
||||
qemu_free(vs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
return ret;
|
||||
|
@ -1095,8 +1145,8 @@ static void reset_keys(VncState *vs)
|
|||
|
||||
static void press_key(VncState *vs, int keysym)
|
||||
{
|
||||
kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) & 0x7f);
|
||||
kbd_put_keycode(keysym2scancode(vs->kbd_layout, keysym) | 0x80);
|
||||
kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) & 0x7f);
|
||||
kbd_put_keycode(keysym2scancode(vs->vd->kbd_layout, keysym) | 0x80);
|
||||
}
|
||||
|
||||
static void do_key_event(VncState *vs, int down, int keycode, int sym)
|
||||
|
@ -1129,12 +1179,12 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym)
|
|||
break;
|
||||
}
|
||||
|
||||
if (keycode_is_keypad(vs->kbd_layout, keycode)) {
|
||||
if (keycode_is_keypad(vs->vd->kbd_layout, keycode)) {
|
||||
/* If the numlock state needs to change then simulate an additional
|
||||
keypress before sending this one. This will happen if the user
|
||||
toggles numlock away from the VNC window.
|
||||
*/
|
||||
if (keysym_is_numlock(vs->kbd_layout, sym & 0xFFFF)) {
|
||||
if (keysym_is_numlock(vs->vd->kbd_layout, sym & 0xFFFF)) {
|
||||
if (!vs->modifiers_state[0x45]) {
|
||||
vs->modifiers_state[0x45] = 1;
|
||||
press_key(vs, 0xff7f);
|
||||
|
@ -1207,7 +1257,7 @@ static void key_event(VncState *vs, int down, uint32_t sym)
|
|||
if (sym >= 'A' && sym <= 'Z' && is_graphic_console())
|
||||
sym = sym - 'A' + 'a';
|
||||
|
||||
keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
|
||||
keycode = keysym2scancode(vs->vd->kbd_layout, sym & 0xFFFF);
|
||||
do_key_event(vs, down, keycode, sym);
|
||||
}
|
||||
|
||||
|
@ -1279,7 +1329,6 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
|
|||
vs->tight_compression = 9;
|
||||
vs->tight_quality = 9;
|
||||
vs->absolute = -1;
|
||||
dcl->dpy_copy = NULL;
|
||||
|
||||
for (i = n_encodings - 1; i >= 0; i--) {
|
||||
enc = encodings[i];
|
||||
|
@ -1288,7 +1337,7 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
|
|||
vs->vnc_encoding = enc;
|
||||
break;
|
||||
case VNC_ENCODING_COPYRECT:
|
||||
dcl->dpy_copy = vnc_copy;
|
||||
vs->features |= VNC_FEATURE_COPYRECT_MASK;
|
||||
break;
|
||||
case VNC_ENCODING_HEXTILE:
|
||||
vs->features |= VNC_FEATURE_HEXTILE_MASK;
|
||||
|
@ -1432,17 +1481,15 @@ static void vnc_dpy_setdata(DisplayState *ds)
|
|||
/* We don't have to do anything */
|
||||
}
|
||||
|
||||
static void vnc_colordepth(DisplayState *ds)
|
||||
static void vnc_colordepth(VncState *vs)
|
||||
{
|
||||
struct VncState *vs = ds->opaque;
|
||||
|
||||
if (vs->csock != -1 && vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
|
||||
if (vnc_has_feature(vs, VNC_FEATURE_WMVI)) {
|
||||
/* Sending a WMVi message to notify the client*/
|
||||
vnc_write_u8(vs, 0); /* msg id */
|
||||
vnc_write_u8(vs, 0);
|
||||
vnc_write_u16(vs, 1); /* number of rects */
|
||||
vnc_framebuffer_update(vs, 0, 0, ds_get_width(ds), ds_get_height(ds),
|
||||
VNC_ENCODING_WMVi);
|
||||
vnc_framebuffer_update(vs, 0, 0, ds_get_width(vs->ds),
|
||||
ds_get_height(vs->ds), VNC_ENCODING_WMVi);
|
||||
pixel_format_message(vs);
|
||||
vnc_flush(vs);
|
||||
} else {
|
||||
|
@ -1626,7 +1673,7 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
|
|||
int i, j, pwlen;
|
||||
unsigned char key[8];
|
||||
|
||||
if (!vs->password || !vs->password[0]) {
|
||||
if (!vs->vd->password || !vs->vd->password[0]) {
|
||||
VNC_DEBUG("No password configured on server");
|
||||
vnc_write_u32(vs, 1); /* Reject auth */
|
||||
if (vs->minor >= 8) {
|
||||
|
@ -1642,9 +1689,9 @@ static int protocol_client_auth_vnc(VncState *vs, uint8_t *data, size_t len)
|
|||
memcpy(response, vs->challenge, VNC_AUTH_CHALLENGE_SIZE);
|
||||
|
||||
/* Calculate the expected challenge response */
|
||||
pwlen = strlen(vs->password);
|
||||
pwlen = strlen(vs->vd->password);
|
||||
for (i=0; i<sizeof(key); i++)
|
||||
key[i] = i<pwlen ? vs->password[i] : 0;
|
||||
key[i] = i<pwlen ? vs->vd->password[i] : 0;
|
||||
deskey(key, EN0);
|
||||
for (j = 0; j < VNC_AUTH_CHALLENGE_SIZE; j += 8)
|
||||
des(response+j, response+j);
|
||||
|
@ -1733,15 +1780,15 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v
|
|||
gnutls_certificate_credentials_t x509_cred;
|
||||
int ret;
|
||||
|
||||
if (!vs->x509cacert) {
|
||||
if (!vs->vd->x509cacert) {
|
||||
VNC_DEBUG("No CA x509 certificate specified\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!vs->x509cert) {
|
||||
if (!vs->vd->x509cert) {
|
||||
VNC_DEBUG("No server x509 certificate specified\n");
|
||||
return NULL;
|
||||
}
|
||||
if (!vs->x509key) {
|
||||
if (!vs->vd->x509key) {
|
||||
VNC_DEBUG("No server private key specified\n");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1751,7 +1798,7 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v
|
|||
return NULL;
|
||||
}
|
||||
if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
|
||||
vs->x509cacert,
|
||||
vs->vd->x509cacert,
|
||||
GNUTLS_X509_FMT_PEM)) < 0) {
|
||||
VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
|
||||
gnutls_certificate_free_credentials(x509_cred);
|
||||
|
@ -1759,17 +1806,17 @@ static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncState *v
|
|||
}
|
||||
|
||||
if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
|
||||
vs->x509cert,
|
||||
vs->x509key,
|
||||
vs->vd->x509cert,
|
||||
vs->vd->x509key,
|
||||
GNUTLS_X509_FMT_PEM)) < 0) {
|
||||
VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
|
||||
gnutls_certificate_free_credentials(x509_cred);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (vs->x509cacrl) {
|
||||
if (vs->vd->x509cacrl) {
|
||||
if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
|
||||
vs->x509cacrl,
|
||||
vs->vd->x509cacrl,
|
||||
GNUTLS_X509_FMT_PEM)) < 0) {
|
||||
VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
|
||||
gnutls_certificate_free_credentials(x509_cred);
|
||||
|
@ -1863,7 +1910,7 @@ static int vnc_validate_certificate(struct VncState *vs)
|
|||
|
||||
static int start_auth_vencrypt_subauth(VncState *vs)
|
||||
{
|
||||
switch (vs->subauth) {
|
||||
switch (vs->vd->subauth) {
|
||||
case VNC_AUTH_VENCRYPT_TLSNONE:
|
||||
case VNC_AUTH_VENCRYPT_X509NONE:
|
||||
VNC_DEBUG("Accept TLS auth none\n");
|
||||
|
@ -1877,7 +1924,7 @@ static int start_auth_vencrypt_subauth(VncState *vs)
|
|||
return start_auth_vnc(vs);
|
||||
|
||||
default: /* Should not be possible, but just in case */
|
||||
VNC_DEBUG("Reject auth %d\n", vs->auth);
|
||||
VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
|
||||
vnc_write_u8(vs, 1);
|
||||
if (vs->minor >= 8) {
|
||||
static const char err[] = "Unsupported authentication type";
|
||||
|
@ -1909,7 +1956,7 @@ static int vnc_continue_handshake(struct VncState *vs) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (vs->x509verify) {
|
||||
if (vs->vd->x509verify) {
|
||||
if (vnc_validate_certificate(vs) < 0) {
|
||||
VNC_DEBUG("Client verification failed\n");
|
||||
vnc_client_error(vs);
|
||||
|
@ -1934,9 +1981,9 @@ static void vnc_handshake_io(void *opaque) {
|
|||
}
|
||||
|
||||
#define NEED_X509_AUTH(vs) \
|
||||
((vs)->subauth == VNC_AUTH_VENCRYPT_X509NONE || \
|
||||
(vs)->subauth == VNC_AUTH_VENCRYPT_X509VNC || \
|
||||
(vs)->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
|
||||
((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE || \
|
||||
(vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC || \
|
||||
(vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN)
|
||||
|
||||
|
||||
static int vnc_start_tls(struct VncState *vs) {
|
||||
|
@ -2000,7 +2047,7 @@ static int vnc_start_tls(struct VncState *vs) {
|
|||
vnc_client_error(vs);
|
||||
return -1;
|
||||
}
|
||||
if (vs->x509verify) {
|
||||
if (vs->vd->x509verify) {
|
||||
VNC_DEBUG("Requesting a client certificate\n");
|
||||
gnutls_certificate_server_set_request (vs->tls_session, GNUTLS_CERT_REQUEST);
|
||||
}
|
||||
|
@ -2035,7 +2082,7 @@ static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len
|
|||
{
|
||||
int auth = read_u32(data, 0);
|
||||
|
||||
if (auth != vs->subauth) {
|
||||
if (auth != vs->vd->subauth) {
|
||||
VNC_DEBUG("Rejecting auth %d\n", auth);
|
||||
vnc_write_u8(vs, 0); /* Reject auth */
|
||||
vnc_flush(vs);
|
||||
|
@ -2070,10 +2117,10 @@ static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len
|
|||
vnc_flush(vs);
|
||||
vnc_client_error(vs);
|
||||
} else {
|
||||
VNC_DEBUG("Sending allowed auth %d\n", vs->subauth);
|
||||
VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
|
||||
vnc_write_u8(vs, 0); /* Accept version */
|
||||
vnc_write_u8(vs, 1); /* Number of sub-auths */
|
||||
vnc_write_u32(vs, vs->subauth); /* The supported auth */
|
||||
vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
|
||||
vnc_flush(vs);
|
||||
vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
|
||||
}
|
||||
|
@ -2095,7 +2142,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
|
|||
{
|
||||
/* We only advertise 1 auth scheme at a time, so client
|
||||
* must pick the one we sent. Verify this */
|
||||
if (data[0] != vs->auth) { /* Reject auth */
|
||||
if (data[0] != vs->vd->auth) { /* Reject auth */
|
||||
VNC_DEBUG("Reject auth %d\n", (int)data[0]);
|
||||
vnc_write_u32(vs, 1);
|
||||
if (vs->minor >= 8) {
|
||||
|
@ -2106,7 +2153,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
|
|||
vnc_client_error(vs);
|
||||
} else { /* Accept requested auth */
|
||||
VNC_DEBUG("Client requested auth %d\n", (int)data[0]);
|
||||
switch (vs->auth) {
|
||||
switch (vs->vd->auth) {
|
||||
case VNC_AUTH_NONE:
|
||||
VNC_DEBUG("Accept auth none\n");
|
||||
if (vs->minor >= 8) {
|
||||
|
@ -2127,7 +2174,7 @@ static int protocol_client_auth(VncState *vs, uint8_t *data, size_t len)
|
|||
#endif /* CONFIG_VNC_TLS */
|
||||
|
||||
default: /* Should not be possible, but just in case */
|
||||
VNC_DEBUG("Reject auth %d\n", vs->auth);
|
||||
VNC_DEBUG("Reject auth %d\n", vs->vd->auth);
|
||||
vnc_write_u8(vs, 1);
|
||||
if (vs->minor >= 8) {
|
||||
static const char err[] = "Authentication failed";
|
||||
|
@ -2172,26 +2219,26 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
|
|||
vs->minor = 3;
|
||||
|
||||
if (vs->minor == 3) {
|
||||
if (vs->auth == VNC_AUTH_NONE) {
|
||||
if (vs->vd->auth == VNC_AUTH_NONE) {
|
||||
VNC_DEBUG("Tell client auth none\n");
|
||||
vnc_write_u32(vs, vs->auth);
|
||||
vnc_write_u32(vs, vs->vd->auth);
|
||||
vnc_flush(vs);
|
||||
vnc_read_when(vs, protocol_client_init, 1);
|
||||
} else if (vs->auth == VNC_AUTH_VNC) {
|
||||
} else if (vs->vd->auth == VNC_AUTH_VNC) {
|
||||
VNC_DEBUG("Tell client VNC auth\n");
|
||||
vnc_write_u32(vs, vs->auth);
|
||||
vnc_write_u32(vs, vs->vd->auth);
|
||||
vnc_flush(vs);
|
||||
start_auth_vnc(vs);
|
||||
} else {
|
||||
VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->auth);
|
||||
VNC_DEBUG("Unsupported auth %d for protocol 3.3\n", vs->vd->auth);
|
||||
vnc_write_u32(vs, VNC_AUTH_INVALID);
|
||||
vnc_flush(vs);
|
||||
vnc_client_error(vs);
|
||||
}
|
||||
} else {
|
||||
VNC_DEBUG("Telling client we support auth %d\n", vs->auth);
|
||||
VNC_DEBUG("Telling client we support auth %d\n", vs->vd->auth);
|
||||
vnc_write_u8(vs, 1); /* num auth */
|
||||
vnc_write_u8(vs, vs->auth);
|
||||
vnc_write_u8(vs, vs->vd->auth);
|
||||
vnc_read_when(vs, protocol_client_auth, 1);
|
||||
vnc_flush(vs);
|
||||
}
|
||||
|
@ -2199,55 +2246,67 @@ static int protocol_version(VncState *vs, uint8_t *version, size_t len)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void vnc_connect(VncState *vs)
|
||||
static void vnc_connect(VncDisplay *vd, int csock)
|
||||
{
|
||||
VNC_DEBUG("New client on socket %d\n", vs->csock);
|
||||
VncState *vs = qemu_mallocz(sizeof(VncState));
|
||||
vs->csock = csock;
|
||||
|
||||
VNC_DEBUG("New client on socket %d\n", csock);
|
||||
dcl->idle = 0;
|
||||
socket_set_nonblock(vs->csock);
|
||||
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs);
|
||||
|
||||
vs->vd = vd;
|
||||
vs->ds = vd->ds;
|
||||
vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
|
||||
vs->last_x = -1;
|
||||
vs->last_y = -1;
|
||||
|
||||
vs->as.freq = 44100;
|
||||
vs->as.nchannels = 2;
|
||||
vs->as.fmt = AUD_FMT_S16;
|
||||
vs->as.endianness = 0;
|
||||
|
||||
vnc_resize(vs);
|
||||
vnc_write(vs, "RFB 003.008\n", 12);
|
||||
vnc_flush(vs);
|
||||
vnc_read_when(vs, protocol_version, 12);
|
||||
memset(vs->old_data, 0, ds_get_linesize(vs->ds) * ds_get_height(vs->ds));
|
||||
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
|
||||
vs->features = 0;
|
||||
dcl->dpy_copy = NULL;
|
||||
vnc_update_client(vs);
|
||||
reset_keys(vs);
|
||||
|
||||
vs->next = vd->clients;
|
||||
vd->clients = vs;
|
||||
}
|
||||
|
||||
static void vnc_listen_read(void *opaque)
|
||||
{
|
||||
VncState *vs = opaque;
|
||||
VncDisplay *vs = opaque;
|
||||
struct sockaddr_in addr;
|
||||
socklen_t addrlen = sizeof(addr);
|
||||
|
||||
/* Catch-up */
|
||||
vga_hw_update();
|
||||
|
||||
vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
|
||||
if (vs->csock != -1) {
|
||||
vnc_connect(vs);
|
||||
int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
|
||||
if (csock != -1) {
|
||||
vnc_connect(vs, csock);
|
||||
}
|
||||
}
|
||||
|
||||
void vnc_display_init(DisplayState *ds)
|
||||
{
|
||||
VncState *vs;
|
||||
VncDisplay *vs;
|
||||
|
||||
vs = qemu_mallocz(sizeof(VncState));
|
||||
dcl = qemu_mallocz(sizeof(DisplayChangeListener));
|
||||
|
||||
ds->opaque = vs;
|
||||
dcl->idle = 1;
|
||||
vnc_state = vs;
|
||||
vs->display = NULL;
|
||||
vs->password = NULL;
|
||||
vnc_display = vs;
|
||||
|
||||
vs->lsock = -1;
|
||||
vs->csock = -1;
|
||||
vs->last_x = -1;
|
||||
vs->last_y = -1;
|
||||
|
||||
vs->ds = ds;
|
||||
|
||||
|
@ -2259,22 +2318,15 @@ void vnc_display_init(DisplayState *ds)
|
|||
if (!vs->kbd_layout)
|
||||
exit(1);
|
||||
|
||||
vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs);
|
||||
|
||||
dcl->dpy_copy = vnc_dpy_copy;
|
||||
dcl->dpy_update = vnc_dpy_update;
|
||||
dcl->dpy_resize = vnc_dpy_resize;
|
||||
dcl->dpy_setdata = vnc_dpy_setdata;
|
||||
dcl->dpy_refresh = NULL;
|
||||
register_displaychangelistener(ds, dcl);
|
||||
|
||||
vs->as.freq = 44100;
|
||||
vs->as.nchannels = 2;
|
||||
vs->as.fmt = AUD_FMT_S16;
|
||||
vs->as.endianness = 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
static int vnc_set_x509_credential(VncState *vs,
|
||||
static int vnc_set_x509_credential(VncDisplay *vs,
|
||||
const char *certdir,
|
||||
const char *filename,
|
||||
char **cred,
|
||||
|
@ -2305,7 +2357,7 @@ static int vnc_set_x509_credential(VncState *vs,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vnc_set_x509_credential_dir(VncState *vs,
|
||||
static int vnc_set_x509_credential_dir(VncDisplay *vs,
|
||||
const char *certdir)
|
||||
{
|
||||
if (vnc_set_x509_credential(vs, certdir, X509_CA_CERT_FILE, &vs->x509cacert, 0) < 0)
|
||||
|
@ -2331,7 +2383,7 @@ static int vnc_set_x509_credential_dir(VncState *vs,
|
|||
|
||||
void vnc_display_close(DisplayState *ds)
|
||||
{
|
||||
VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
|
||||
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
|
||||
|
||||
if (!vs)
|
||||
return;
|
||||
|
@ -2344,32 +2396,16 @@ void vnc_display_close(DisplayState *ds)
|
|||
close(vs->lsock);
|
||||
vs->lsock = -1;
|
||||
}
|
||||
if (vs->csock != -1) {
|
||||
qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
|
||||
closesocket(vs->csock);
|
||||
vs->csock = -1;
|
||||
buffer_reset(&vs->input);
|
||||
buffer_reset(&vs->output);
|
||||
vs->need_update = 0;
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
if (vs->tls_session) {
|
||||
gnutls_deinit(vs->tls_session);
|
||||
vs->tls_session = NULL;
|
||||
}
|
||||
vs->wiremode = VNC_WIREMODE_CLEAR;
|
||||
#endif /* CONFIG_VNC_TLS */
|
||||
}
|
||||
vs->auth = VNC_AUTH_INVALID;
|
||||
#ifdef CONFIG_VNC_TLS
|
||||
vs->subauth = VNC_AUTH_INVALID;
|
||||
vs->x509verify = 0;
|
||||
#endif
|
||||
audio_del(vs);
|
||||
}
|
||||
|
||||
int vnc_display_password(DisplayState *ds, const char *password)
|
||||
{
|
||||
VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
|
||||
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
|
||||
|
||||
if (vs->password) {
|
||||
qemu_free(vs->password);
|
||||
|
@ -2385,7 +2421,7 @@ int vnc_display_password(DisplayState *ds, const char *password)
|
|||
|
||||
int vnc_display_open(DisplayState *ds, const char *display)
|
||||
{
|
||||
VncState *vs = ds ? (VncState *)ds->opaque : vnc_state;
|
||||
VncDisplay *vs = ds ? (VncDisplay *)ds->opaque : vnc_display;
|
||||
const char *options;
|
||||
int password = 0;
|
||||
int reverse = 0;
|
||||
|
@ -2394,7 +2430,7 @@ int vnc_display_open(DisplayState *ds, const char *display)
|
|||
int tls = 0, x509 = 0;
|
||||
#endif
|
||||
|
||||
if (!vnc_state)
|
||||
if (!vnc_display)
|
||||
return -1;
|
||||
vnc_display_close(ds);
|
||||
if (strcmp(display, "none") == 0)
|
||||
|
@ -2499,9 +2535,9 @@ int vnc_display_open(DisplayState *ds, const char *display)
|
|||
vs->display = NULL;
|
||||
return -1;
|
||||
} else {
|
||||
vs->csock = vs->lsock;
|
||||
int csock = vs->lsock;
|
||||
vs->lsock = -1;
|
||||
vnc_connect(vs);
|
||||
vnc_connect(vs, csock);
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
@ -2523,6 +2559,5 @@ int vnc_display_open(DisplayState *ds, const char *display)
|
|||
vs->display = dpy;
|
||||
}
|
||||
}
|
||||
|
||||
return qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
|
||||
return qemu_set_fd_handler2(vs->lsock, NULL, vnc_listen_read, NULL, vs);
|
||||
}
|
||||
|
|
2
vnc.h
2
vnc.h
|
@ -101,6 +101,7 @@ enum {
|
|||
#define VNC_FEATURE_WMVI 3
|
||||
#define VNC_FEATURE_TIGHT 4
|
||||
#define VNC_FEATURE_ZLIB 5
|
||||
#define VNC_FEATURE_COPYRECT 6
|
||||
|
||||
#define VNC_FEATURE_RESIZE_MASK (1 << VNC_FEATURE_RESIZE)
|
||||
#define VNC_FEATURE_HEXTILE_MASK (1 << VNC_FEATURE_HEXTILE)
|
||||
|
@ -108,5 +109,6 @@ enum {
|
|||
#define VNC_FEATURE_WMVI_MASK (1 << VNC_FEATURE_WMVI)
|
||||
#define VNC_FEATURE_TIGHT_MASK (1 << VNC_FEATURE_TIGHT)
|
||||
#define VNC_FEATURE_ZLIB_MASK (1 << VNC_FEATURE_ZLIB)
|
||||
#define VNC_FEATURE_COPYRECT_MASK (1 << VNC_FEATURE_COPYRECT)
|
||||
|
||||
#endif /* __VNCTIGHT_H */
|
||||
|
|
Loading…
Reference in New Issue