2
* Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
4
* This program is free software; you can redistribute it and/or modify
5
* it under the terms of the GNU Lesser General Public License version 2 as
6
* published by the Free Software Foundation.
13
#include <sys/socket.h>
14
#include <netinet/in.h>
15
#include <arpa/inet.h>
28
#include "coroutine.h"
31
static gboolean g_io_wait_helper(GIOChannel *channel, GIOCondition cond,
34
struct coroutine *to = data;
39
GIOCondition g_io_wait(GIOChannel *channel, GIOCondition cond)
43
g_io_add_watch(channel, cond, g_io_wait_helper, coroutine_self());
49
typedef void gvnc_blt_func(struct gvnc *, uint8_t *, int, int, int, int, int);
51
typedef void gvnc_hextile_func(struct gvnc *gvnc, uint8_t flags,
52
uint16_t x, uint16_t y,
53
uint16_t width, uint16_t height,
54
uint8_t *fg, uint8_t *bg);
59
struct vnc_pixel_format fmt;
65
char read_buffer[4096];
69
gboolean perfect_match;
70
struct framebuffer local;
76
gvnc_hextile_func *hextile;
84
#define GVNC_DEBUG(fmt, ...) do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
86
#define GVNC_DEBUG(fmt, ...) do { } while (0)
89
#define nibhi(a) (((a) >> 4) & 0x0F)
90
#define niblo(a) ((a) & 0x0F)
94
static void gvnc_read(struct gvnc *gvnc, void *data, size_t len)
96
int fd = g_io_channel_unix_get_fd(gvnc->channel);
100
if (gvnc->has_error) return;
102
while (offset < len) {
105
if (gvnc->read_offset == gvnc->read_size) {
108
ret = read(fd, gvnc->read_buffer, 4096);
112
g_io_wait(gvnc->channel, G_IO_IN);
116
gvnc->has_error = TRUE;
121
gvnc->has_error = TRUE;
125
gvnc->read_offset = 0;
126
gvnc->read_size = ret;
129
tmp = MIN(gvnc->read_size - gvnc->read_offset, len - offset);
131
memcpy(ptr + offset, gvnc->read_buffer + gvnc->read_offset, tmp);
133
gvnc->read_offset += tmp;
138
void gvnc_write(struct gvnc *gvnc, const void *data, size_t len)
140
int fd = g_io_channel_unix_get_fd(gvnc->channel);
141
const char *ptr = data;
144
while (offset < len) {
147
ret = write(fd, ptr + offset, len - offset);
151
g_io_wait(gvnc->channel, G_IO_OUT);
155
gvnc->has_error = TRUE;
161
gvnc->has_error = TRUE;
169
static uint8_t gvnc_read_u8(struct gvnc *gvnc)
172
gvnc_read(gvnc, &value, sizeof(value));
176
static uint16_t gvnc_read_u16(struct gvnc *gvnc)
179
gvnc_read(gvnc, &value, sizeof(value));
183
static uint32_t gvnc_read_u32(struct gvnc *gvnc)
186
gvnc_read(gvnc, &value, sizeof(value));
190
static int32_t gvnc_read_s32(struct gvnc *gvnc)
193
gvnc_read(gvnc, &value, sizeof(value));
197
static void gvnc_write_u8(struct gvnc *gvnc, uint8_t value)
199
gvnc_write(gvnc, &value, sizeof(value));
202
static void gvnc_write_u16(struct gvnc *gvnc, uint16_t value)
204
value = htons(value);
205
gvnc_write(gvnc, &value, sizeof(value));
208
static void gvnc_write_u32(struct gvnc *gvnc, uint32_t value)
210
value = htonl(value);
211
gvnc_write(gvnc, &value, sizeof(value));
214
static void gvnc_write_s32(struct gvnc *gvnc, int32_t value)
216
value = htonl(value);
217
gvnc_write(gvnc, &value, sizeof(value));
220
static void gvnc_read_pixel_format(struct gvnc *gvnc, struct vnc_pixel_format *fmt)
224
fmt->bits_per_pixel = gvnc_read_u8(gvnc);
225
fmt->depth = gvnc_read_u8(gvnc);
226
fmt->big_endian_flag = gvnc_read_u8(gvnc);
227
fmt->true_color_flag = gvnc_read_u8(gvnc);
229
fmt->red_max = gvnc_read_u16(gvnc);
230
fmt->green_max = gvnc_read_u16(gvnc);
231
fmt->blue_max = gvnc_read_u16(gvnc);
233
fmt->red_shift = gvnc_read_u8(gvnc);
234
fmt->green_shift = gvnc_read_u8(gvnc);
235
fmt->blue_shift = gvnc_read_u8(gvnc);
237
gvnc_read(gvnc, pad, 3);
240
/* initialize function */
242
gboolean gvnc_has_error(struct gvnc *gvnc)
244
return gvnc->has_error;
247
gboolean gvnc_set_pixel_format(struct gvnc *gvnc,
248
const struct vnc_pixel_format *fmt)
250
uint8_t pad[3] = {0};
252
gvnc_write_u8(gvnc, 0);
253
gvnc_write(gvnc, pad, 3);
255
gvnc_write_u8(gvnc, fmt->bits_per_pixel);
256
gvnc_write_u8(gvnc, fmt->depth);
257
gvnc_write_u8(gvnc, fmt->big_endian_flag);
258
gvnc_write_u8(gvnc, fmt->true_color_flag);
260
gvnc_write_u16(gvnc, fmt->red_max);
261
gvnc_write_u16(gvnc, fmt->green_max);
262
gvnc_write_u16(gvnc, fmt->blue_max);
264
gvnc_write_u8(gvnc, fmt->red_shift);
265
gvnc_write_u8(gvnc, fmt->green_shift);
266
gvnc_write_u8(gvnc, fmt->blue_shift);
268
gvnc_write(gvnc, pad, 3);
270
memcpy(&gvnc->fmt, fmt, sizeof(*fmt));
272
return gvnc_has_error(gvnc);
275
gboolean gvnc_set_encodings(struct gvnc *gvnc, int n_encoding, int32_t *encoding)
277
uint8_t pad[1] = {0};
280
gvnc_write_u8(gvnc, 2);
281
gvnc_write(gvnc, pad, 1);
282
gvnc_write_u16(gvnc, n_encoding);
283
for (i = 0; i < n_encoding; i++)
284
gvnc_write_s32(gvnc, encoding[i]);
286
return gvnc_has_error(gvnc);
289
gboolean gvnc_framebuffer_update_request(struct gvnc *gvnc,
291
uint16_t x, uint16_t y,
292
uint16_t width, uint16_t height)
294
gvnc_write_u8(gvnc, 3);
295
gvnc_write_u8(gvnc, incremental);
296
gvnc_write_u16(gvnc, x);
297
gvnc_write_u16(gvnc, y);
298
gvnc_write_u16(gvnc, width);
299
gvnc_write_u16(gvnc, height);
301
return gvnc_has_error(gvnc);
304
gboolean gvnc_key_event(struct gvnc *gvnc, uint8_t down_flag, uint32_t key)
306
uint8_t pad[2] = {0};
308
gvnc_write_u8(gvnc, 4);
309
gvnc_write_u8(gvnc, down_flag);
310
gvnc_write(gvnc, pad, 2);
311
gvnc_write_u32(gvnc, key);
313
return gvnc_has_error(gvnc);
316
gboolean gvnc_pointer_event(struct gvnc *gvnc, uint8_t button_mask,
317
uint16_t x, uint16_t y)
319
gvnc_write_u8(gvnc, 5);
320
gvnc_write_u8(gvnc, button_mask);
321
gvnc_write_u16(gvnc, x);
322
gvnc_write_u16(gvnc, y);
324
return gvnc_has_error(gvnc);
327
gboolean gvnc_client_cut_text(struct gvnc *gvnc,
328
const void *data, size_t length)
330
uint8_t pad[3] = {0};
332
gvnc_write_u8(gvnc, 6);
333
gvnc_write(gvnc, pad, 3);
334
gvnc_write_u32(gvnc, length);
335
gvnc_write(gvnc, data, length);
337
return gvnc_has_error(gvnc);
340
static inline uint8_t *gvnc_get_local(struct gvnc *gvnc, int x, int y)
342
return gvnc->local.data +
343
(y * gvnc->local.linesize) +
344
(x * gvnc->local.bpp);
347
#define SPLICE_I(a, b) a ## b
348
#define SPLICE(a, b) SPLICE_I(a, b)
362
static gvnc_blt_func *gvnc_blt_table[3][3] = {
363
{ gvnc_blt_8x8, gvnc_blt_8x16, gvnc_blt_8x32 },
364
{ gvnc_blt_16x8, gvnc_blt_16x16, gvnc_blt_16x32 },
365
{ gvnc_blt_32x8, gvnc_blt_32x16, gvnc_blt_32x32 },
368
static gvnc_hextile_func *gvnc_hextile_table[3][3] = {
369
{ (gvnc_hextile_func *)gvnc_hextile_8x8,
370
(gvnc_hextile_func *)gvnc_hextile_8x16,
371
(gvnc_hextile_func *)gvnc_hextile_8x32 },
372
{ (gvnc_hextile_func *)gvnc_hextile_16x8,
373
(gvnc_hextile_func *)gvnc_hextile_16x16,
374
(gvnc_hextile_func *)gvnc_hextile_16x32 },
375
{ (gvnc_hextile_func *)gvnc_hextile_32x8,
376
(gvnc_hextile_func *)gvnc_hextile_32x16,
377
(gvnc_hextile_func *)gvnc_hextile_32x32 },
380
/* a fast blit for the perfect match scenario */
381
static void gvnc_blt_fast(struct gvnc *gvnc, uint8_t *src, int pitch,
382
int x, int y, int width, int height)
384
uint8_t *dst = gvnc_get_local(gvnc, x, y);
386
for (i = 0; i < height; i++) {
387
memcpy(dst, src, width * gvnc->local.bpp);
388
dst += gvnc->local.linesize;
393
static void gvnc_blt(struct gvnc *gvnc, uint8_t *src, int pitch,
394
int x, int y, int width, int height)
396
gvnc->blt(gvnc, src, pitch, x, y, width, height);
399
static void gvnc_raw_update(struct gvnc *gvnc,
400
uint16_t x, uint16_t y,
401
uint16_t width, uint16_t height)
406
/* optimize for perfect match between server/client
407
FWIW, in the local case, we ought to be doing a write
408
directly from the source framebuffer and a read directly
409
into the client framebuffer
411
if (gvnc->perfect_match) {
412
dst = gvnc_get_local(gvnc, x, y);
413
for (i = 0; i < height; i++) {
414
gvnc_read(gvnc, dst, width * gvnc->local.bpp);
415
dst += gvnc->local.linesize;
420
dst = malloc(width * (gvnc->fmt.bits_per_pixel / 8));
422
gvnc->has_error = TRUE;
426
for (i = 0; i < height; i++) {
427
gvnc_read(gvnc, dst, width * (gvnc->fmt.bits_per_pixel / 8));
428
gvnc_blt(gvnc, dst, 0, x, y + i, width, 1);
434
static void gvnc_copyrect_update(struct gvnc *gvnc,
435
uint16_t dst_x, uint16_t dst_y,
436
uint16_t width, uint16_t height)
440
int pitch = gvnc->local.linesize;
443
src_x = gvnc_read_u16(gvnc);
444
src_y = gvnc_read_u16(gvnc);
448
src_y += (height - 1);
449
dst_y += (height - 1);
452
dst = gvnc_get_local(gvnc, dst_x, dst_y);
453
src = gvnc_get_local(gvnc, src_x, src_y);
454
for (i = 0; i < height; i++) {
455
memmove(dst, src, width * gvnc->local.bpp);
461
static void gvnc_hextile_update(struct gvnc *gvnc,
462
uint16_t x, uint16_t y,
463
uint16_t width, uint16_t height)
469
for (j = 0; j < height; j += 16) {
471
for (i = 0; i < width; i += 16) {
473
int w = MIN(16, width - i);
474
int h = MIN(16, height - j);
476
flags = gvnc_read_u8(gvnc);
477
gvnc->hextile(gvnc, flags, x + i, y + j, w, h, fg, bg);
482
static void gvnc_update(struct gvnc *gvnc, int x, int y, int width, int height)
484
if (gvnc->has_error || !gvnc->ops.update)
486
gvnc->has_error = !gvnc->ops.update(gvnc->ops.user, x, y, width, height);
489
static void gvnc_set_color_map_entry(struct gvnc *gvnc, uint16_t color,
490
uint16_t red, uint16_t green,
493
if (gvnc->has_error || !gvnc->ops.set_color_map_entry)
495
gvnc->has_error = !gvnc->ops.set_color_map_entry(gvnc->ops.user, color,
499
static void gvnc_bell(struct gvnc *gvnc)
501
if (gvnc->has_error || !gvnc->ops.bell)
503
gvnc->has_error = !gvnc->ops.bell(gvnc->ops.user);
506
static void gvnc_server_cut_text(struct gvnc *gvnc, const void *data,
509
if (gvnc->has_error || !gvnc->ops.server_cut_text)
511
gvnc->has_error = !gvnc->ops.server_cut_text(gvnc->ops.user, data, len);
514
static void gvnc_resize(struct gvnc *gvnc, int width, int height)
516
if (gvnc->has_error || !gvnc->ops.resize)
518
gvnc->has_error = !gvnc->ops.resize(gvnc->ops.user, width, height);
521
static void gvnc_pointer_type_change(struct gvnc *gvnc, int absolute)
523
if (gvnc->has_error || !gvnc->ops.pointer_type_change)
525
gvnc->has_error = !gvnc->ops.pointer_type_change(gvnc->ops.user, absolute);
528
static void gvnc_framebuffer_update(struct gvnc *gvnc, int32_t etype,
529
uint16_t x, uint16_t y,
530
uint16_t width, uint16_t height)
532
GVNC_DEBUG("FramebufferUpdate(%d, %d, %d, %d, %d)\n",
533
etype, x, y, width, height);
537
gvnc_raw_update(gvnc, x, y, width, height);
539
case 1: /* CopyRect */
540
gvnc_copyrect_update(gvnc, x, y, width, height);
542
case 5: /* Hextile */
543
gvnc_hextile_update(gvnc, x, y, width, height);
545
case -223: /* DesktopResize */
546
gvnc_resize(gvnc, width, height);
548
case -257: /* PointerChangeType */
549
gvnc_pointer_type_change(gvnc, x);
552
gvnc->has_error = TRUE;
556
gvnc_update(gvnc, x, y, width, height);
559
gboolean gvnc_server_message(struct gvnc *gvnc)
563
/* NB: make sure that all server message functions
564
handle has_error appropriately */
566
msg = gvnc_read_u8(gvnc);
568
case 0: { /* FramebufferUpdate */
573
gvnc_read(gvnc, pad, 1);
574
n_rects = gvnc_read_u16(gvnc);
575
for (i = 0; i < n_rects; i++) {
579
x = gvnc_read_u16(gvnc);
580
y = gvnc_read_u16(gvnc);
581
w = gvnc_read_u16(gvnc);
582
h = gvnc_read_u16(gvnc);
583
etype = gvnc_read_s32(gvnc);
585
gvnc_framebuffer_update(gvnc, etype, x, y, w, h);
588
case 1: { /* SetColorMapEntries */
589
uint16_t first_color;
594
gvnc_read(gvnc, pad, 1);
595
first_color = gvnc_read_u16(gvnc);
596
n_colors = gvnc_read_u16(gvnc);
598
for (i = 0; i < n_colors; i++) {
599
uint16_t red, green, blue;
601
red = gvnc_read_u16(gvnc);
602
green = gvnc_read_u16(gvnc);
603
blue = gvnc_read_u16(gvnc);
605
gvnc_set_color_map_entry(gvnc,
613
case 3: { /* ServerCutText */
618
gvnc_read(gvnc, pad, 3);
619
n_text = gvnc_read_u32(gvnc);
620
if (n_text > (32 << 20)) {
621
gvnc->has_error = TRUE;
625
data = malloc(n_text + 1);
627
gvnc->has_error = TRUE;
631
gvnc_read(gvnc, data, n_text);
634
gvnc_server_cut_text(gvnc, data, n_text);
638
gvnc->has_error = TRUE;
642
return gvnc_has_error(gvnc);
645
struct gvnc *gvnc_connect(GIOChannel *channel, gboolean shared_flag, const char *password)
653
struct gvnc *gvnc = NULL;
655
s = g_io_channel_unix_get_fd(channel);
657
if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
660
gvnc = malloc(sizeof(*gvnc));
664
memset(gvnc, 0, sizeof(*gvnc));
666
gvnc->channel = channel;
669
gvnc_read(gvnc, version, 12);
672
ret = sscanf(version, "RFB %03d.%03d\n", &major, &minor);
676
gvnc_write(gvnc, "RFB 003.003\n", 12);
678
auth = gvnc_read_u32(gvnc);
683
uint8_t challenge[16];
687
gvnc_read(gvnc, challenge, 16);
690
strncpy((char*)key, (char*)password, 8);
693
des(challenge, challenge);
694
des(challenge + 8, challenge + 8);
696
gvnc_write(gvnc, challenge, 16);
698
result = gvnc_read_u32(gvnc);
707
gvnc_write_u8(gvnc, shared_flag); /* shared flag */
709
gvnc->width = gvnc_read_u16(gvnc);
710
gvnc->height = gvnc_read_u16(gvnc);
712
gvnc_read_pixel_format(gvnc, &gvnc->fmt);
714
n_name = gvnc_read_u32(gvnc);
718
gvnc->name = malloc(n_name + 1);
719
if (gvnc->name == NULL)
722
gvnc_read(gvnc, gvnc->name, n_name);
723
gvnc->name[n_name] = 0;
725
gvnc_resize(gvnc, gvnc->width, gvnc->height);
734
gboolean gvnc_set_local(struct gvnc *gvnc, struct framebuffer *fb)
739
memcpy(&gvnc->local, fb, sizeof(*fb));
741
if (fb->bpp == (gvnc->fmt.bits_per_pixel / 8) &&
742
fb->red_mask == gvnc->fmt.red_max &&
743
fb->green_mask == gvnc->fmt.green_max &&
744
fb->blue_mask == gvnc->fmt.blue_max &&
745
fb->red_shift == gvnc->fmt.red_shift &&
746
fb->green_shift == gvnc->fmt.green_shift &&
747
fb->blue_shift == gvnc->fmt.blue_shift)
748
gvnc->perfect_match = TRUE;
750
gvnc->perfect_match = FALSE;
752
depth = gvnc->fmt.depth;
756
gvnc->rp = (gvnc->local.depth - gvnc->local.red_shift);
757
gvnc->rp -= (depth - gvnc->fmt.red_shift);
758
gvnc->gp = (gvnc->local.red_shift - gvnc->local.green_shift);
759
gvnc->gp -= (gvnc->fmt.red_shift - gvnc->fmt.green_shift);
760
gvnc->bp = (gvnc->local.green_shift - gvnc->local.blue_shift);
761
gvnc->bp -= (gvnc->fmt.green_shift - gvnc->fmt.blue_shift);
763
gvnc->rp = gvnc->local.red_shift + gvnc->rp;
764
gvnc->gp = gvnc->local.green_shift + gvnc->gp;
765
gvnc->bp = gvnc->local.blue_shift + gvnc->bp;
767
gvnc->rm = gvnc->local.red_mask & gvnc->fmt.red_max;
768
gvnc->gm = gvnc->local.green_mask & gvnc->fmt.green_max;
769
gvnc->bm = gvnc->local.blue_mask & gvnc->fmt.blue_max;
771
i = gvnc->fmt.bits_per_pixel / 8;
777
gvnc->blt = gvnc_blt_table[i - 1][j - 1];
778
gvnc->hextile = gvnc_hextile_table[i - 1][j - 1];
780
if (gvnc->perfect_match)
781
gvnc->blt = gvnc_blt_fast;
783
return gvnc_has_error(gvnc);
786
gboolean gvnc_set_vnc_ops(struct gvnc *gvnc, struct vnc_ops *ops)
788
memcpy(&gvnc->ops, ops, sizeof(*ops));
789
gvnc_resize(gvnc, gvnc->width, gvnc->height);
790
return gvnc_has_error(gvnc);
793
const char *gvnc_get_name(struct gvnc *gvnc)