root / vnc.c @ 6ca957f0
History | View | Annotate | Download (20.1 kB)
1 |
#include "vl.h" |
---|---|
2 |
#include "qemu_socket.h" |
3 |
|
4 |
#define VNC_REFRESH_INTERVAL (1000 / 30) |
5 |
|
6 |
#include "vnc_keysym.h" |
7 |
#include "keymaps.c" |
8 |
|
9 |
typedef struct Buffer |
10 |
{ |
11 |
size_t capacity; |
12 |
size_t offset; |
13 |
char *buffer;
|
14 |
} Buffer; |
15 |
|
16 |
typedef struct VncState VncState; |
17 |
|
18 |
typedef int VncReadEvent(VncState *vs, char *data, size_t len); |
19 |
|
20 |
struct VncState
|
21 |
{ |
22 |
QEMUTimer *timer; |
23 |
int lsock;
|
24 |
int csock;
|
25 |
DisplayState *ds; |
26 |
int need_update;
|
27 |
int width;
|
28 |
int height;
|
29 |
uint64_t dirty_row[768];
|
30 |
char *old_data;
|
31 |
int depth;
|
32 |
int has_resize;
|
33 |
int has_hextile;
|
34 |
Buffer output; |
35 |
Buffer input; |
36 |
kbd_layout_t *kbd_layout; |
37 |
|
38 |
VncReadEvent *read_handler; |
39 |
size_t read_handler_expect; |
40 |
}; |
41 |
|
42 |
/* TODO
|
43 |
1) Get the queue working for IO.
|
44 |
2) there is some weirdness when using the -S option (the screen is grey
|
45 |
and not totally invalidated
|
46 |
3) resolutions > 1024
|
47 |
*/
|
48 |
|
49 |
static void vnc_write(VncState *vs, const void *data, size_t len); |
50 |
static void vnc_write_u32(VncState *vs, uint32_t value); |
51 |
static void vnc_write_s32(VncState *vs, int32_t value); |
52 |
static void vnc_write_u16(VncState *vs, uint16_t value); |
53 |
static void vnc_write_u8(VncState *vs, uint8_t value); |
54 |
static void vnc_flush(VncState *vs); |
55 |
static void vnc_update_client(void *opaque); |
56 |
static void vnc_client_read(void *opaque); |
57 |
|
58 |
static void vnc_dpy_update(DisplayState *ds, int x, int y, int w, int h) |
59 |
{ |
60 |
VncState *vs = ds->opaque; |
61 |
int i;
|
62 |
|
63 |
h += y; |
64 |
|
65 |
for (; y < h; y++)
|
66 |
for (i = 0; i < w; i += 16) |
67 |
vs->dirty_row[y] |= (1ULL << ((x + i) / 16)); |
68 |
} |
69 |
|
70 |
static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h, |
71 |
int32_t encoding) |
72 |
{ |
73 |
vnc_write_u16(vs, x); |
74 |
vnc_write_u16(vs, y); |
75 |
vnc_write_u16(vs, w); |
76 |
vnc_write_u16(vs, h); |
77 |
|
78 |
vnc_write_s32(vs, encoding); |
79 |
} |
80 |
|
81 |
static void vnc_dpy_resize(DisplayState *ds, int w, int h) |
82 |
{ |
83 |
VncState *vs = ds->opaque; |
84 |
|
85 |
ds->data = realloc(ds->data, w * h * vs->depth); |
86 |
vs->old_data = realloc(vs->old_data, w * h * vs->depth); |
87 |
|
88 |
if (ds->data == NULL || vs->old_data == NULL) { |
89 |
fprintf(stderr, "vnc: memory allocation failed\n");
|
90 |
exit(1);
|
91 |
} |
92 |
|
93 |
ds->depth = vs->depth * 8;
|
94 |
ds->width = w; |
95 |
ds->height = h; |
96 |
ds->linesize = w * vs->depth; |
97 |
if (vs->csock != -1 && vs->has_resize) { |
98 |
vnc_write_u8(vs, 0); /* msg id */ |
99 |
vnc_write_u8(vs, 0);
|
100 |
vnc_write_u16(vs, 1); /* number of rects */ |
101 |
vnc_framebuffer_update(vs, 0, 0, ds->width, ds->height, -223); |
102 |
vnc_flush(vs); |
103 |
vs->width = ds->width; |
104 |
vs->height = ds->height; |
105 |
} |
106 |
} |
107 |
|
108 |
static void send_framebuffer_update_raw(VncState *vs, int x, int y, int w, int h) |
109 |
{ |
110 |
int i;
|
111 |
char *row;
|
112 |
|
113 |
vnc_framebuffer_update(vs, x, y, w, h, 0);
|
114 |
|
115 |
row = vs->ds->data + y * vs->ds->linesize + x * vs->depth; |
116 |
for (i = 0; i < h; i++) { |
117 |
vnc_write(vs, row, w * vs->depth); |
118 |
row += vs->ds->linesize; |
119 |
} |
120 |
} |
121 |
|
122 |
static void hextile_enc_cord(uint8_t *ptr, int x, int y, int w, int h) |
123 |
{ |
124 |
ptr[0] = ((x & 0x0F) << 4) | (y & 0x0F); |
125 |
ptr[1] = (((w - 1) & 0x0F) << 4) | ((h - 1) & 0x0F); |
126 |
} |
127 |
|
128 |
#define BPP 8 |
129 |
#include "vnchextile.h" |
130 |
#undef BPP
|
131 |
|
132 |
#define BPP 16 |
133 |
#include "vnchextile.h" |
134 |
#undef BPP
|
135 |
|
136 |
#define BPP 32 |
137 |
#include "vnchextile.h" |
138 |
#undef BPP
|
139 |
|
140 |
static void send_framebuffer_update_hextile(VncState *vs, int x, int y, int w, int h) |
141 |
{ |
142 |
int i, j;
|
143 |
int has_fg, has_bg;
|
144 |
uint32_t last_fg32, last_bg32; |
145 |
uint16_t last_fg16, last_bg16; |
146 |
uint8_t last_fg8, last_bg8; |
147 |
|
148 |
vnc_framebuffer_update(vs, x, y, w, h, 5);
|
149 |
|
150 |
has_fg = has_bg = 0;
|
151 |
for (j = y; j < (y + h); j += 16) { |
152 |
for (i = x; i < (x + w); i += 16) { |
153 |
switch (vs->depth) {
|
154 |
case 1: |
155 |
send_hextile_tile_8(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), |
156 |
&last_bg8, &last_fg8, &has_bg, &has_fg); |
157 |
break;
|
158 |
case 2: |
159 |
send_hextile_tile_16(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), |
160 |
&last_bg16, &last_fg16, &has_bg, &has_fg); |
161 |
break;
|
162 |
case 4: |
163 |
send_hextile_tile_32(vs, i, j, MIN(16, x + w - i), MIN(16, y + h - j), |
164 |
&last_bg32, &last_fg32, &has_bg, &has_fg); |
165 |
break;
|
166 |
default:
|
167 |
break;
|
168 |
} |
169 |
} |
170 |
} |
171 |
} |
172 |
|
173 |
static void send_framebuffer_update(VncState *vs, int x, int y, int w, int h) |
174 |
{ |
175 |
if (vs->has_hextile)
|
176 |
send_framebuffer_update_hextile(vs, x, y, w, h); |
177 |
else
|
178 |
send_framebuffer_update_raw(vs, x, y, w, h); |
179 |
} |
180 |
|
181 |
static void vnc_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int dst_y, int w, int h) |
182 |
{ |
183 |
int src, dst;
|
184 |
char *src_row;
|
185 |
char *dst_row;
|
186 |
char *old_row;
|
187 |
int y = 0; |
188 |
int pitch = ds->linesize;
|
189 |
VncState *vs = ds->opaque; |
190 |
|
191 |
vnc_update_client(vs); |
192 |
|
193 |
if (dst_y > src_y) {
|
194 |
y = h - 1;
|
195 |
pitch = -pitch; |
196 |
} |
197 |
|
198 |
src = (ds->linesize * (src_y + y) + vs->depth * src_x); |
199 |
dst = (ds->linesize * (dst_y + y) + vs->depth * dst_x); |
200 |
|
201 |
src_row = ds->data + src; |
202 |
dst_row = ds->data + dst; |
203 |
old_row = vs->old_data + dst; |
204 |
|
205 |
for (y = 0; y < h; y++) { |
206 |
memmove(old_row, src_row, w * vs->depth); |
207 |
memmove(dst_row, src_row, w * vs->depth); |
208 |
src_row += pitch; |
209 |
dst_row += pitch; |
210 |
old_row += pitch; |
211 |
} |
212 |
|
213 |
vnc_write_u8(vs, 0); /* msg id */ |
214 |
vnc_write_u8(vs, 0);
|
215 |
vnc_write_u16(vs, 1); /* number of rects */ |
216 |
vnc_framebuffer_update(vs, dst_x, dst_y, w, h, 1);
|
217 |
vnc_write_u16(vs, src_x); |
218 |
vnc_write_u16(vs, src_y); |
219 |
vnc_flush(vs); |
220 |
} |
221 |
|
222 |
static int find_dirty_height(VncState *vs, int y, int last_x, int x) |
223 |
{ |
224 |
int h;
|
225 |
|
226 |
for (h = 1; h < (vs->height - y); h++) { |
227 |
int tmp_x;
|
228 |
if (!(vs->dirty_row[y + h] & (1ULL << last_x))) |
229 |
break;
|
230 |
for (tmp_x = last_x; tmp_x < x; tmp_x++)
|
231 |
vs->dirty_row[y + h] &= ~(1ULL << tmp_x);
|
232 |
} |
233 |
|
234 |
return h;
|
235 |
} |
236 |
|
237 |
static void vnc_update_client(void *opaque) |
238 |
{ |
239 |
VncState *vs = opaque; |
240 |
|
241 |
if (vs->need_update && vs->csock != -1) { |
242 |
int y;
|
243 |
char *row;
|
244 |
char *old_row;
|
245 |
uint64_t width_mask; |
246 |
int n_rectangles;
|
247 |
int saved_offset;
|
248 |
int has_dirty = 0; |
249 |
|
250 |
width_mask = (1ULL << (vs->width / 16)) - 1; |
251 |
|
252 |
if (vs->width == 1024) |
253 |
width_mask = ~(0ULL);
|
254 |
|
255 |
/* Walk through the dirty map and eliminate tiles that
|
256 |
really aren't dirty */
|
257 |
row = vs->ds->data; |
258 |
old_row = vs->old_data; |
259 |
|
260 |
for (y = 0; y < vs->height; y++) { |
261 |
if (vs->dirty_row[y] & width_mask) {
|
262 |
int x;
|
263 |
char *ptr, *old_ptr;
|
264 |
|
265 |
ptr = row; |
266 |
old_ptr = old_row; |
267 |
|
268 |
for (x = 0; x < vs->ds->width; x += 16) { |
269 |
if (memcmp(old_ptr, ptr, 16 * vs->depth) == 0) { |
270 |
vs->dirty_row[y] &= ~(1ULL << (x / 16)); |
271 |
} else {
|
272 |
has_dirty = 1;
|
273 |
memcpy(old_ptr, ptr, 16 * vs->depth);
|
274 |
} |
275 |
|
276 |
ptr += 16 * vs->depth;
|
277 |
old_ptr += 16 * vs->depth;
|
278 |
} |
279 |
} |
280 |
|
281 |
row += vs->ds->linesize; |
282 |
old_row += vs->ds->linesize; |
283 |
} |
284 |
|
285 |
if (!has_dirty) {
|
286 |
qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); |
287 |
return;
|
288 |
} |
289 |
|
290 |
/* Count rectangles */
|
291 |
n_rectangles = 0;
|
292 |
vnc_write_u8(vs, 0); /* msg id */ |
293 |
vnc_write_u8(vs, 0);
|
294 |
saved_offset = vs->output.offset; |
295 |
vnc_write_u16(vs, 0);
|
296 |
|
297 |
for (y = 0; y < vs->height; y++) { |
298 |
int x;
|
299 |
int last_x = -1; |
300 |
for (x = 0; x < vs->width / 16; x++) { |
301 |
if (vs->dirty_row[y] & (1ULL << x)) { |
302 |
if (last_x == -1) { |
303 |
last_x = x; |
304 |
} |
305 |
vs->dirty_row[y] &= ~(1ULL << x);
|
306 |
} else {
|
307 |
if (last_x != -1) { |
308 |
int h = find_dirty_height(vs, y, last_x, x);
|
309 |
send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h); |
310 |
n_rectangles++; |
311 |
} |
312 |
last_x = -1;
|
313 |
} |
314 |
} |
315 |
if (last_x != -1) { |
316 |
int h = find_dirty_height(vs, y, last_x, x);
|
317 |
send_framebuffer_update(vs, last_x * 16, y, (x - last_x) * 16, h); |
318 |
n_rectangles++; |
319 |
} |
320 |
} |
321 |
vs->output.buffer[saved_offset] = (n_rectangles >> 8) & 0xFF; |
322 |
vs->output.buffer[saved_offset + 1] = n_rectangles & 0xFF; |
323 |
vnc_flush(vs); |
324 |
|
325 |
} |
326 |
qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock) + VNC_REFRESH_INTERVAL); |
327 |
} |
328 |
|
329 |
static void vnc_timer_init(VncState *vs) |
330 |
{ |
331 |
if (vs->timer == NULL) { |
332 |
vs->timer = qemu_new_timer(rt_clock, vnc_update_client, vs); |
333 |
qemu_mod_timer(vs->timer, qemu_get_clock(rt_clock)); |
334 |
} |
335 |
} |
336 |
|
337 |
static void vnc_dpy_refresh(DisplayState *ds) |
338 |
{ |
339 |
VncState *vs = ds->opaque; |
340 |
vnc_timer_init(vs); |
341 |
vga_hw_update(); |
342 |
} |
343 |
|
344 |
static int vnc_listen_poll(void *opaque) |
345 |
{ |
346 |
VncState *vs = opaque; |
347 |
if (vs->csock == -1) |
348 |
return 1; |
349 |
return 0; |
350 |
} |
351 |
|
352 |
static void buffer_reserve(Buffer *buffer, size_t len) |
353 |
{ |
354 |
if ((buffer->capacity - buffer->offset) < len) {
|
355 |
buffer->capacity += (len + 1024);
|
356 |
buffer->buffer = realloc(buffer->buffer, buffer->capacity); |
357 |
if (buffer->buffer == NULL) { |
358 |
fprintf(stderr, "vnc: out of memory\n");
|
359 |
exit(1);
|
360 |
} |
361 |
} |
362 |
} |
363 |
|
364 |
static int buffer_empty(Buffer *buffer) |
365 |
{ |
366 |
return buffer->offset == 0; |
367 |
} |
368 |
|
369 |
static char *buffer_end(Buffer *buffer) |
370 |
{ |
371 |
return buffer->buffer + buffer->offset;
|
372 |
} |
373 |
|
374 |
static void buffer_reset(Buffer *buffer) |
375 |
{ |
376 |
buffer->offset = 0;
|
377 |
} |
378 |
|
379 |
static void buffer_append(Buffer *buffer, const void *data, size_t len) |
380 |
{ |
381 |
memcpy(buffer->buffer + buffer->offset, data, len); |
382 |
buffer->offset += len; |
383 |
} |
384 |
|
385 |
static int vnc_client_io_error(VncState *vs, int ret, int last_errno) |
386 |
{ |
387 |
if (ret == 0 || ret == -1) { |
388 |
if (ret == -1 && (last_errno == EINTR || last_errno == EAGAIN)) |
389 |
return 0; |
390 |
|
391 |
qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL); |
392 |
closesocket(vs->csock); |
393 |
vs->csock = -1;
|
394 |
buffer_reset(&vs->input); |
395 |
buffer_reset(&vs->output); |
396 |
vs->need_update = 0;
|
397 |
return 0; |
398 |
} |
399 |
return ret;
|
400 |
} |
401 |
|
402 |
static void vnc_client_error(VncState *vs) |
403 |
{ |
404 |
vnc_client_io_error(vs, -1, EINVAL);
|
405 |
} |
406 |
|
407 |
static void vnc_client_write(void *opaque) |
408 |
{ |
409 |
ssize_t ret; |
410 |
VncState *vs = opaque; |
411 |
|
412 |
ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
|
413 |
ret = vnc_client_io_error(vs, ret, socket_error()); |
414 |
if (!ret)
|
415 |
return;
|
416 |
|
417 |
memmove(vs->output.buffer, vs->output.buffer + ret, (vs->output.offset - ret)); |
418 |
vs->output.offset -= ret; |
419 |
|
420 |
if (vs->output.offset == 0) { |
421 |
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, vs); |
422 |
} |
423 |
} |
424 |
|
425 |
static void vnc_read_when(VncState *vs, VncReadEvent *func, size_t expecting) |
426 |
{ |
427 |
vs->read_handler = func; |
428 |
vs->read_handler_expect = expecting; |
429 |
} |
430 |
|
431 |
static void vnc_client_read(void *opaque) |
432 |
{ |
433 |
VncState *vs = opaque; |
434 |
ssize_t ret; |
435 |
|
436 |
buffer_reserve(&vs->input, 4096);
|
437 |
|
438 |
ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0); |
439 |
ret = vnc_client_io_error(vs, ret, socket_error()); |
440 |
if (!ret)
|
441 |
return;
|
442 |
|
443 |
vs->input.offset += ret; |
444 |
|
445 |
while (vs->read_handler && vs->input.offset >= vs->read_handler_expect) {
|
446 |
size_t len = vs->read_handler_expect; |
447 |
int ret;
|
448 |
|
449 |
ret = vs->read_handler(vs, vs->input.buffer, len); |
450 |
if (vs->csock == -1) |
451 |
return;
|
452 |
|
453 |
if (!ret) {
|
454 |
memmove(vs->input.buffer, vs->input.buffer + len, (vs->input.offset - len)); |
455 |
vs->input.offset -= len; |
456 |
} else {
|
457 |
vs->read_handler_expect = ret; |
458 |
} |
459 |
} |
460 |
} |
461 |
|
462 |
static void vnc_write(VncState *vs, const void *data, size_t len) |
463 |
{ |
464 |
buffer_reserve(&vs->output, len); |
465 |
|
466 |
if (buffer_empty(&vs->output)) {
|
467 |
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
|
468 |
} |
469 |
|
470 |
buffer_append(&vs->output, data, len); |
471 |
} |
472 |
|
473 |
static void vnc_write_s32(VncState *vs, int32_t value) |
474 |
{ |
475 |
vnc_write_u32(vs, *(uint32_t *)&value); |
476 |
} |
477 |
|
478 |
static void vnc_write_u32(VncState *vs, uint32_t value) |
479 |
{ |
480 |
uint8_t buf[4];
|
481 |
|
482 |
buf[0] = (value >> 24) & 0xFF; |
483 |
buf[1] = (value >> 16) & 0xFF; |
484 |
buf[2] = (value >> 8) & 0xFF; |
485 |
buf[3] = value & 0xFF; |
486 |
|
487 |
vnc_write(vs, buf, 4);
|
488 |
} |
489 |
|
490 |
static void vnc_write_u16(VncState *vs, uint16_t value) |
491 |
{ |
492 |
char buf[2]; |
493 |
|
494 |
buf[0] = (value >> 8) & 0xFF; |
495 |
buf[1] = value & 0xFF; |
496 |
|
497 |
vnc_write(vs, buf, 2);
|
498 |
} |
499 |
|
500 |
static void vnc_write_u8(VncState *vs, uint8_t value) |
501 |
{ |
502 |
vnc_write(vs, (char *)&value, 1); |
503 |
} |
504 |
|
505 |
static void vnc_flush(VncState *vs) |
506 |
{ |
507 |
if (vs->output.offset)
|
508 |
vnc_client_write(vs); |
509 |
} |
510 |
|
511 |
static uint8_t read_u8(char *data, size_t offset) |
512 |
{ |
513 |
return data[offset];
|
514 |
} |
515 |
|
516 |
static uint16_t read_u16(char *data, size_t offset) |
517 |
{ |
518 |
return ((data[offset] & 0xFF) << 8) | (data[offset + 1] & 0xFF); |
519 |
} |
520 |
|
521 |
static int32_t read_s32(char *data, size_t offset) |
522 |
{ |
523 |
return (int32_t)((data[offset] << 24) | (data[offset + 1] << 16) | |
524 |
(data[offset + 2] << 8) | data[offset + 3]); |
525 |
} |
526 |
|
527 |
static uint32_t read_u32(char *data, size_t offset) |
528 |
{ |
529 |
return ((data[offset] << 24) | (data[offset + 1] << 16) | |
530 |
(data[offset + 2] << 8) | data[offset + 3]); |
531 |
} |
532 |
|
533 |
static void client_cut_text(VncState *vs, size_t len, char *text) |
534 |
{ |
535 |
} |
536 |
|
537 |
static void pointer_event(VncState *vs, int button_mask, int x, int y) |
538 |
{ |
539 |
int buttons = 0; |
540 |
int dz = 0; |
541 |
|
542 |
if (button_mask & 0x01) |
543 |
buttons |= MOUSE_EVENT_LBUTTON; |
544 |
if (button_mask & 0x02) |
545 |
buttons |= MOUSE_EVENT_MBUTTON; |
546 |
if (button_mask & 0x04) |
547 |
buttons |= MOUSE_EVENT_RBUTTON; |
548 |
if (button_mask & 0x08) |
549 |
dz = -1;
|
550 |
if (button_mask & 0x10) |
551 |
dz = 1;
|
552 |
|
553 |
if (kbd_mouse_is_absolute()) {
|
554 |
kbd_mouse_event(x * 0x7FFF / vs->ds->width,
|
555 |
y * 0x7FFF / vs->ds->height,
|
556 |
dz, buttons); |
557 |
} else {
|
558 |
static int last_x = -1; |
559 |
static int last_y = -1; |
560 |
|
561 |
if (last_x != -1) |
562 |
kbd_mouse_event(x - last_x, y - last_y, dz, buttons); |
563 |
|
564 |
last_x = x; |
565 |
last_y = y; |
566 |
} |
567 |
} |
568 |
|
569 |
static void key_event(VncState *vs, int down, uint32_t sym) |
570 |
{ |
571 |
int keycode;
|
572 |
|
573 |
keycode = keysym2scancode(vs->kbd_layout, sym & 0xFFFF);
|
574 |
|
575 |
if (keycode & 0x80) |
576 |
kbd_put_keycode(0xe0);
|
577 |
if (down)
|
578 |
kbd_put_keycode(keycode & 0x7f);
|
579 |
else
|
580 |
kbd_put_keycode(keycode | 0x80);
|
581 |
} |
582 |
|
583 |
static void framebuffer_update_request(VncState *vs, int incremental, |
584 |
int x_position, int y_position, |
585 |
int w, int h) |
586 |
{ |
587 |
int i;
|
588 |
vs->need_update = 1;
|
589 |
if (!incremental) {
|
590 |
char *old_row = vs->old_data + y_position * vs->ds->linesize;
|
591 |
|
592 |
for (i = 0; i < h; i++) { |
593 |
vs->dirty_row[y_position + i] = (1ULL << (vs->ds->width / 16)) - 1; |
594 |
if (vs->ds->width == 1024) { |
595 |
vs->dirty_row[y_position + i] = ~(0ULL);
|
596 |
} |
597 |
memset(old_row, 42, vs->ds->width * vs->depth);
|
598 |
old_row += vs->ds->linesize; |
599 |
} |
600 |
} |
601 |
} |
602 |
|
603 |
static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings) |
604 |
{ |
605 |
int i;
|
606 |
|
607 |
vs->has_hextile = 0;
|
608 |
vs->has_resize = 0;
|
609 |
vs->ds->dpy_copy = NULL;
|
610 |
|
611 |
for (i = n_encodings - 1; i >= 0; i--) { |
612 |
switch (encodings[i]) {
|
613 |
case 0: /* Raw */ |
614 |
vs->has_hextile = 0;
|
615 |
break;
|
616 |
case 1: /* CopyRect */ |
617 |
vs->ds->dpy_copy = vnc_copy; |
618 |
break;
|
619 |
case 5: /* Hextile */ |
620 |
vs->has_hextile = 1;
|
621 |
break;
|
622 |
case -223: /* DesktopResize */ |
623 |
vs->has_resize = 1;
|
624 |
break;
|
625 |
default:
|
626 |
break;
|
627 |
} |
628 |
} |
629 |
} |
630 |
|
631 |
static void set_pixel_format(VncState *vs, |
632 |
int bits_per_pixel, int depth, |
633 |
int big_endian_flag, int true_color_flag, |
634 |
int red_max, int green_max, int blue_max, |
635 |
int red_shift, int green_shift, int blue_shift) |
636 |
{ |
637 |
switch (bits_per_pixel) {
|
638 |
case 32: |
639 |
case 24: |
640 |
vs->depth = 4;
|
641 |
break;
|
642 |
case 16: |
643 |
vs->depth = 2;
|
644 |
break;
|
645 |
case 8: |
646 |
vs->depth = 1;
|
647 |
break;
|
648 |
default:
|
649 |
vnc_client_error(vs); |
650 |
break;
|
651 |
} |
652 |
|
653 |
if (!true_color_flag)
|
654 |
vnc_client_error(vs); |
655 |
|
656 |
vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height); |
657 |
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); |
658 |
memset(vs->old_data, 42, vs->ds->linesize * vs->ds->height);
|
659 |
|
660 |
vga_hw_invalidate(); |
661 |
vga_hw_update(); |
662 |
} |
663 |
|
664 |
static int protocol_client_msg(VncState *vs, char *data, size_t len) |
665 |
{ |
666 |
int i;
|
667 |
uint16_t limit; |
668 |
|
669 |
switch (data[0]) { |
670 |
case 0: |
671 |
if (len == 1) |
672 |
return 20; |
673 |
|
674 |
set_pixel_format(vs, read_u8(data, 4), read_u8(data, 5), |
675 |
read_u8(data, 6), read_u8(data, 7), |
676 |
read_u16(data, 8), read_u16(data, 10), |
677 |
read_u16(data, 12), read_u8(data, 14), |
678 |
read_u8(data, 15), read_u8(data, 16)); |
679 |
break;
|
680 |
case 2: |
681 |
if (len == 1) |
682 |
return 4; |
683 |
|
684 |
if (len == 4) |
685 |
return 4 + (read_u16(data, 2) * 4); |
686 |
|
687 |
limit = read_u16(data, 2);
|
688 |
for (i = 0; i < limit; i++) { |
689 |
int32_t val = read_s32(data, 4 + (i * 4)); |
690 |
memcpy(data + 4 + (i * 4), &val, sizeof(val)); |
691 |
} |
692 |
|
693 |
set_encodings(vs, (int32_t *)(data + 4), limit);
|
694 |
break;
|
695 |
case 3: |
696 |
if (len == 1) |
697 |
return 10; |
698 |
|
699 |
framebuffer_update_request(vs, |
700 |
read_u8(data, 1), read_u16(data, 2), read_u16(data, 4), |
701 |
read_u16(data, 6), read_u16(data, 8)); |
702 |
break;
|
703 |
case 4: |
704 |
if (len == 1) |
705 |
return 8; |
706 |
|
707 |
key_event(vs, read_u8(data, 1), read_u32(data, 4)); |
708 |
break;
|
709 |
case 5: |
710 |
if (len == 1) |
711 |
return 6; |
712 |
|
713 |
pointer_event(vs, read_u8(data, 1), read_u16(data, 2), read_u16(data, 4)); |
714 |
break;
|
715 |
case 6: |
716 |
if (len == 1) |
717 |
return 8; |
718 |
|
719 |
if (len == 8) |
720 |
return 8 + read_u32(data, 4); |
721 |
|
722 |
client_cut_text(vs, read_u32(data, 4), data + 8); |
723 |
break;
|
724 |
default:
|
725 |
printf("Msg: %d\n", data[0]); |
726 |
vnc_client_error(vs); |
727 |
break;
|
728 |
} |
729 |
|
730 |
vnc_read_when(vs, protocol_client_msg, 1);
|
731 |
return 0; |
732 |
} |
733 |
|
734 |
static int protocol_client_init(VncState *vs, char *data, size_t len) |
735 |
{ |
736 |
char pad[3] = { 0, 0, 0 }; |
737 |
|
738 |
vs->width = vs->ds->width; |
739 |
vs->height = vs->ds->height; |
740 |
vnc_write_u16(vs, vs->ds->width); |
741 |
vnc_write_u16(vs, vs->ds->height); |
742 |
|
743 |
vnc_write_u8(vs, vs->depth * 8); /* bits-per-pixel */ |
744 |
vnc_write_u8(vs, vs->depth * 8); /* depth */ |
745 |
vnc_write_u8(vs, 0); /* big-endian-flag */ |
746 |
vnc_write_u8(vs, 1); /* true-color-flag */ |
747 |
if (vs->depth == 4) { |
748 |
vnc_write_u16(vs, 0xFF); /* red-max */ |
749 |
vnc_write_u16(vs, 0xFF); /* green-max */ |
750 |
vnc_write_u16(vs, 0xFF); /* blue-max */ |
751 |
vnc_write_u8(vs, 16); /* red-shift */ |
752 |
vnc_write_u8(vs, 8); /* green-shift */ |
753 |
vnc_write_u8(vs, 0); /* blue-shift */ |
754 |
} else if (vs->depth == 2) { |
755 |
vnc_write_u16(vs, 31); /* red-max */ |
756 |
vnc_write_u16(vs, 63); /* green-max */ |
757 |
vnc_write_u16(vs, 31); /* blue-max */ |
758 |
vnc_write_u8(vs, 11); /* red-shift */ |
759 |
vnc_write_u8(vs, 5); /* green-shift */ |
760 |
vnc_write_u8(vs, 0); /* blue-shift */ |
761 |
} else if (vs->depth == 1) { |
762 |
vnc_write_u16(vs, 3); /* red-max */ |
763 |
vnc_write_u16(vs, 7); /* green-max */ |
764 |
vnc_write_u16(vs, 3); /* blue-max */ |
765 |
vnc_write_u8(vs, 5); /* red-shift */ |
766 |
vnc_write_u8(vs, 2); /* green-shift */ |
767 |
vnc_write_u8(vs, 0); /* blue-shift */ |
768 |
} |
769 |
|
770 |
vnc_write(vs, pad, 3); /* padding */ |
771 |
|
772 |
vnc_write_u32(vs, 4);
|
773 |
vnc_write(vs, "QEMU", 4); |
774 |
vnc_flush(vs); |
775 |
|
776 |
vnc_read_when(vs, protocol_client_msg, 1);
|
777 |
|
778 |
return 0; |
779 |
} |
780 |
|
781 |
static int protocol_version(VncState *vs, char *version, size_t len) |
782 |
{ |
783 |
char local[13]; |
784 |
int maj, min;
|
785 |
|
786 |
memcpy(local, version, 12);
|
787 |
local[12] = 0; |
788 |
|
789 |
if (sscanf(local, "RFB %03d.%03d\n", &maj, &min) != 2) { |
790 |
vnc_client_error(vs); |
791 |
return 0; |
792 |
} |
793 |
|
794 |
vnc_write_u32(vs, 1); /* None */ |
795 |
vnc_flush(vs); |
796 |
|
797 |
vnc_read_when(vs, protocol_client_init, 1);
|
798 |
|
799 |
return 0; |
800 |
} |
801 |
|
802 |
static void vnc_listen_read(void *opaque) |
803 |
{ |
804 |
VncState *vs = opaque; |
805 |
struct sockaddr_in addr;
|
806 |
socklen_t addrlen = sizeof(addr);
|
807 |
|
808 |
vs->csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen);
|
809 |
if (vs->csock != -1) { |
810 |
socket_set_nonblock(vs->csock); |
811 |
qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, NULL, opaque); |
812 |
vnc_write(vs, "RFB 003.003\n", 12); |
813 |
vnc_flush(vs); |
814 |
vnc_read_when(vs, protocol_version, 12);
|
815 |
memset(vs->old_data, 0, vs->ds->linesize * vs->ds->height);
|
816 |
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); |
817 |
vs->has_resize = 0;
|
818 |
vs->has_hextile = 0;
|
819 |
vs->ds->dpy_copy = NULL;
|
820 |
} |
821 |
} |
822 |
|
823 |
void vnc_display_init(DisplayState *ds, int display) |
824 |
{ |
825 |
struct sockaddr_in addr;
|
826 |
int reuse_addr, ret;
|
827 |
VncState *vs; |
828 |
|
829 |
vs = qemu_mallocz(sizeof(VncState));
|
830 |
if (!vs)
|
831 |
exit(1);
|
832 |
|
833 |
ds->opaque = vs; |
834 |
|
835 |
vs->lsock = -1;
|
836 |
vs->csock = -1;
|
837 |
vs->depth = 4;
|
838 |
|
839 |
vs->ds = ds; |
840 |
|
841 |
if (!keyboard_layout)
|
842 |
keyboard_layout = "en-us";
|
843 |
|
844 |
vs->kbd_layout = init_keyboard_layout(keyboard_layout); |
845 |
if (!vs->kbd_layout)
|
846 |
exit(1);
|
847 |
|
848 |
vs->lsock = socket(PF_INET, SOCK_STREAM, 0);
|
849 |
if (vs->lsock == -1) { |
850 |
fprintf(stderr, "Could not create socket\n");
|
851 |
exit(1);
|
852 |
} |
853 |
|
854 |
addr.sin_family = AF_INET; |
855 |
addr.sin_port = htons(5900 + display);
|
856 |
memset(&addr.sin_addr, 0, sizeof(addr.sin_addr)); |
857 |
|
858 |
reuse_addr = 1;
|
859 |
ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR, |
860 |
(const char *)&reuse_addr, sizeof(reuse_addr)); |
861 |
if (ret == -1) { |
862 |
fprintf(stderr, "setsockopt() failed\n");
|
863 |
exit(1);
|
864 |
} |
865 |
|
866 |
if (bind(vs->lsock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { |
867 |
fprintf(stderr, "bind() failed\n");
|
868 |
exit(1);
|
869 |
} |
870 |
|
871 |
if (listen(vs->lsock, 1) == -1) { |
872 |
fprintf(stderr, "listen() failed\n");
|
873 |
exit(1);
|
874 |
} |
875 |
|
876 |
ret = qemu_set_fd_handler2(vs->lsock, vnc_listen_poll, vnc_listen_read, NULL, vs);
|
877 |
if (ret == -1) { |
878 |
exit(1);
|
879 |
} |
880 |
|
881 |
vs->ds->data = NULL;
|
882 |
vs->ds->dpy_update = vnc_dpy_update; |
883 |
vs->ds->dpy_resize = vnc_dpy_resize; |
884 |
vs->ds->dpy_refresh = vnc_dpy_refresh; |
885 |
|
886 |
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row)); |
887 |
|
888 |
vnc_dpy_resize(vs->ds, 640, 400); |
889 |
} |