source: mainline/uspace/srv/hid/rfb/rfb.c@ 2c9f6dd3

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2c9f6dd3 was 2c9f6dd3, checked in by Martin Sucha <sucha14@…>, 12 years ago

rfb: Add a basic support for pallete-based pixel mode

  • Property mode set to 100644
File size: 15.4 KB
Line 
1/*
2 * Copyright (c) 2013 Martin Sucha
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <errno.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <fibril_synch.h>
33#include <inttypes.h>
34#include <str.h>
35#include <str_error.h>
36#include <byteorder.h>
37#include <macros.h>
38
39#include <net/in.h>
40#include <net/inet.h>
41#include <net/socket.h>
42
43#include "rfb.h"
44
45/** Buffer for receiving the request. */
46#define BUFFER_SIZE 1024
47
48static char rbuf[BUFFER_SIZE];
49static size_t rbuf_out;
50static size_t rbuf_in;
51
52
53/** Receive one character (with buffering) */
54static int recv_char(int fd, char *c)
55{
56 if (rbuf_out == rbuf_in) {
57 rbuf_out = 0;
58 rbuf_in = 0;
59
60 ssize_t rc = recv(fd, rbuf, BUFFER_SIZE, 0);
61 if (rc <= 0) {
62 fprintf(stderr, "recv() failed (%zd)\n", rc);
63 return rc;
64 }
65
66 rbuf_in = rc;
67 }
68
69 *c = rbuf[rbuf_out++];
70 return EOK;
71}
72
73/** Receive count characters (with buffering) */
74static int recv_chars(int fd, char *c, size_t count)
75{
76 for (size_t i = 0; i < count; i++) {
77 int rc = recv_char(fd, c);
78 if (rc != EOK)
79 return rc;
80 c++;
81 }
82 return EOK;
83}
84
85static int recv_skip_chars(int fd, size_t count)
86{
87 for (size_t i = 0; i < count; i++) {
88 char c;
89 int rc = recv_char(fd, &c);
90 if (rc != EOK)
91 return rc;
92 }
93 return EOK;
94}
95
96static void rfb_pixel_format_to_be(rfb_pixel_format_t *src, rfb_pixel_format_t *dst)
97{
98 dst->r_max = host2uint16_t_be(src->r_max);
99 dst->g_max = host2uint16_t_be(src->g_max);
100 dst->b_max = host2uint16_t_be(src->b_max);
101}
102
103static void rfb_pixel_format_to_host(rfb_pixel_format_t *src, rfb_pixel_format_t *dst)
104{
105 dst->r_max = uint16_t_be2host(src->r_max);
106 dst->g_max = uint16_t_be2host(src->g_max);
107 dst->b_max = uint16_t_be2host(src->b_max);
108}
109
110static void rfb_server_init_to_be(rfb_server_init_t *src, rfb_server_init_t *dst)
111{
112 dst->width = host2uint16_t_be(src->width);
113 dst->height = host2uint16_t_be(src->height);
114 rfb_pixel_format_to_be(&src->pixel_format, &dst->pixel_format);
115 dst->name_length = host2uint32_t_be(src->name_length);
116}
117
118static void rfb_set_encodings_to_host(rfb_set_encodings_t *src, rfb_set_encodings_t *dst)
119{
120 dst->count = uint16_t_be2host(src->count);
121}
122
123static void rfb_framebuffer_update_request_to_host(rfb_framebuffer_update_request_t *src,
124 rfb_framebuffer_update_request_t *dst)
125{
126 dst->x = uint16_t_be2host(src->x);
127 dst->y = uint16_t_be2host(src->x);
128 dst->width = uint16_t_be2host(src->width);
129 dst->height = uint16_t_be2host(src->height);
130}
131
132static void rfb_framebuffer_update_to_be(rfb_framebuffer_update_t *src,
133 rfb_framebuffer_update_t *dst)
134{
135 dst->rect_count = host2uint16_t_be(src->rect_count);
136}
137
138static void rfb_rectangle_to_be(rfb_rectangle_t *src, rfb_rectangle_t *dst)
139{
140 dst->x = host2uint16_t_be(src->x);
141 dst->y = host2uint16_t_be(src->y);
142 dst->width = host2uint16_t_be(src->width);
143 dst->height = host2uint16_t_be(src->height);
144 dst->enctype = host2uint32_t_be(src->enctype);
145}
146
147static void rfb_key_event_to_host(rfb_key_event_t *src, rfb_key_event_t *dst)
148{
149 dst->key = uint32_t_be2host(src->key);
150}
151
152static void rfb_pointer_event_to_host(rfb_pointer_event_t *src, rfb_pointer_event_t *dst)
153{
154 dst->x = uint16_t_be2host(src->x);
155 dst->y = uint16_t_be2host(src->y);
156}
157
158static void rfb_client_cut_text_to_host(rfb_client_cut_text_t *src,
159 rfb_client_cut_text_t *dst)
160{
161 dst->length = uint32_t_be2host(src->length);
162}
163
164int rfb_init(rfb_t *rfb, uint16_t width, uint16_t height, const char *name)
165{
166 memset(rfb, 0, sizeof(rfb_t));
167 fibril_mutex_initialize(&rfb->lock);
168
169 rfb_pixel_format_t *pf = &rfb->pixel_format;
170 pf->bpp = 32;
171 pf->depth = 24;
172 pf->big_endian = 1;
173 pf->true_color = 1;
174 pf->r_max = 255;
175 pf->g_max = 255;
176 pf->b_max = 255;
177 pf->r_shift = 0;
178 pf->g_shift = 8;
179 pf->b_shift = 16;
180
181 rfb->name = str_dup(name);
182
183 return rfb_set_size(rfb, width, height);
184}
185
186int rfb_set_size(rfb_t *rfb, uint16_t width, uint16_t height)
187{
188 size_t new_size = width * height * sizeof(pixel_t);
189 void *pixbuf = malloc(new_size);
190 if (pixbuf == NULL)
191 return ENOMEM;
192
193 free(rfb->framebuffer.data);
194 rfb->framebuffer.data = pixbuf;
195 rfb->framebuffer.width = width;
196 rfb->framebuffer.height = height;
197 rfb->width = width;
198 rfb->height = height;
199
200 /* Fill with white */
201 memset(rfb->framebuffer.data, 255, new_size);
202
203 return EOK;
204}
205
206static int recv_message(int conn_sd, char type, void *buf, size_t size)
207{
208 memcpy(buf, &type, 1);
209 return recv_chars(conn_sd, ((char *) buf) + 1, size -1);
210}
211
212static uint32_t rfb_scale_channel(uint8_t val, uint32_t max)
213{
214 return val * max / 255;
215}
216
217static void rfb_encode_index(rfb_t *rfb, uint8_t *buf, pixel_t pixel)
218{
219 int first_free_index = -1;
220 for (size_t i = 0; i < 256; i++) {
221 bool free = ALPHA(rfb->palette[i]) == 0;
222 if (free && first_free_index == -1) {
223 first_free_index = i;
224 }
225 else if (!free && RED(rfb->palette[i]) == RED(pixel) &&
226 GREEN(rfb->palette[i]) == GREEN(pixel) &&
227 BLUE(rfb->palette[i]) == BLUE(pixel)) {
228 *buf = i;
229 return;
230 }
231 }
232
233 if (first_free_index != -1) {
234 rfb->palette[first_free_index] = PIXEL(255, RED(pixel), GREEN(pixel),
235 BLUE(pixel));
236 rfb->palette_used = max(rfb->palette_used, (unsigned) first_free_index + 1);
237 *buf = first_free_index;
238 return;
239 }
240
241 /* TODO find nearest color index. We are lazy so return index 0 for now */
242 *buf = 0;
243}
244
245static void rfb_encode_true_color(rfb_pixel_format_t *pf, void *buf,
246 pixel_t pixel)
247{
248 uint32_t pix = 0;
249 pix |= rfb_scale_channel(RED(pixel), pf->r_max) << pf->r_shift;
250 pix |= rfb_scale_channel(GREEN(pixel), pf->g_max) << pf->g_shift;
251 pix |= rfb_scale_channel(BLUE(pixel), pf->b_max) << pf->b_shift;
252
253 if (pf->bpp == 8) {
254 uint8_t pix8 = pix;
255 memcpy(buf, &pix8, 1);
256 }
257 else if (pf->bpp == 16) {
258 uint16_t pix16 = pix;
259 if (pf->big_endian) {
260 pix16 = host2uint16_t_be(pix16);
261 }
262 else {
263 pix16 = host2uint16_t_le(pix16);
264 }
265 memcpy(buf, &pix16, 2);
266 }
267 else if (pf->bpp == 32) {
268 if (pf->big_endian) {
269 pix = host2uint32_t_be(pix);
270 }
271 else {
272 pix = host2uint32_t_le(pix);
273 }
274 memcpy(buf, &pix, 4);
275 }
276}
277
278static void rfb_encode_pixel(rfb_t *rfb, void *buf, pixel_t pixel)
279{
280 if (rfb->pixel_format.true_color) {
281 rfb_encode_true_color(&rfb->pixel_format, buf, pixel);
282 }
283 else {
284 rfb_encode_index(rfb, buf, pixel);
285 }
286}
287
288static void rfb_set_color_map_entries_to_be(rfb_set_color_map_entries_t *src,
289 rfb_set_color_map_entries_t *dst)
290{
291 dst->first_color = host2uint16_t_be(src->first_color);
292 dst->color_count = host2uint16_t_be(src->color_count);
293}
294
295static void rfb_color_map_entry_to_be(rfb_color_map_entry_t *src,
296 rfb_color_map_entry_t *dst)
297{
298 dst->red = host2uint16_t_be(src->red);
299 dst->green = host2uint16_t_be(src->green);
300 dst->blue = host2uint16_t_be(src->blue);
301}
302
303static int rfb_send_palette(int conn_sd, rfb_t *rfb)
304{
305 size_t size = sizeof(rfb_set_color_map_entries_t) +
306 rfb->palette_used * sizeof(rfb_color_map_entry_t);
307
308 void *buf = malloc(size);
309 if (buf == NULL)
310 return ENOMEM;
311
312 void *pos = buf;
313
314 rfb_set_color_map_entries_t *scme = pos;
315 scme->message_type = RFB_SMSG_SET_COLOR_MAP_ENTRIES;
316 scme->first_color = 0;
317 scme->color_count = rfb->palette_used;
318 rfb_set_color_map_entries_to_be(scme, scme);
319 pos += sizeof(rfb_set_color_map_entries_t);
320
321 rfb_color_map_entry_t *entries = pos;
322 for (unsigned i = 0; i < rfb->palette_used; i++) {
323 entries[i].red = 65535 * RED(rfb->palette[i]) / 255;
324 entries[i].green = 65535 * GREEN(rfb->palette[i]) / 255;
325 entries[i].blue = 65535 * BLUE(rfb->palette[i]) / 255;
326 rfb_color_map_entry_to_be(&entries[i], &entries[i]);
327 }
328
329 int rc = send(conn_sd, buf, size, 0);
330 free(buf);
331
332 return rc;
333}
334
335static int rfb_send_framebuffer_update(rfb_t *rfb, int conn_sd, bool incremental)
336{
337 if (!incremental || !rfb->damage_valid) {
338 rfb->damage_rect.x = 0;
339 rfb->damage_rect.y = 0;
340 rfb->damage_rect.width = rfb->width;
341 rfb->damage_rect.height = rfb->height;
342 }
343
344
345 /* We send only single raw rectangle right now */
346 size_t buf_size = sizeof(rfb_framebuffer_update_t) +
347 sizeof(rfb_rectangle_t) * 1 +
348 (rfb->damage_rect.width * rfb->damage_rect.height * (rfb->pixel_format.bpp/8));
349
350 void *buf = malloc(buf_size);
351 if (buf == NULL)
352 return ENOMEM;
353 memset(buf, 0, buf_size);
354
355 void *pos = buf;
356 rfb_framebuffer_update_t *fbu = buf;
357 fbu->message_type = RFB_SMSG_FRAMEBUFFER_UPDATE;
358 fbu->rect_count = 1;
359 rfb_framebuffer_update_to_be(fbu, fbu);
360 pos += sizeof(rfb_framebuffer_update_t);
361
362 rfb_rectangle_t *rect = pos;
363 *rect = rfb->damage_rect;
364 rect->enctype = RFB_ENCODING_RAW;
365 rfb_rectangle_to_be(rect, rect);
366 pos += sizeof(rfb_rectangle_t);
367
368 size_t pixel_size = rfb->pixel_format.bpp / 8;
369
370 for (uint16_t y = 0; y < rfb->damage_rect.height; y++) {
371 for (uint16_t x = 0; x < rfb->damage_rect.width; x++) {
372 pixel_t pixel = pixelmap_get_pixel(&rfb->framebuffer,
373 x + rfb->damage_rect.x, y + rfb->damage_rect.y);
374 rfb_encode_pixel(rfb, pos, pixel);
375 pos += pixel_size;
376 }
377 }
378
379 if (!rfb->pixel_format.true_color) {
380 int rc = rfb_send_palette(conn_sd, rfb);
381 if (rc != EOK) {
382 free(buf);
383 return rc;
384 }
385 }
386
387 int rc = send(conn_sd, buf, buf_size, 0);
388 free(buf);
389 rfb->damage_valid = false;
390 return rc;
391}
392
393static int rfb_set_pixel_format(rfb_t *rfb, rfb_pixel_format_t *pixel_format)
394{
395 rfb->pixel_format = *pixel_format;
396 if (rfb->pixel_format.true_color) {
397 free(rfb->palette);
398 rfb->palette = NULL;
399 rfb->palette_used = 0;
400 }
401 else {
402 if (rfb->palette == NULL) {
403 rfb->palette = malloc(sizeof(pixel_t) * 256);
404 if (rfb->palette == NULL)
405 return ENOMEM;
406 memset(rfb->palette, 0, sizeof(pixel_t) * 256);
407 rfb->palette_used = 0;
408 }
409 }
410 return EOK;
411}
412
413static void rfb_socket_connection(rfb_t *rfb, int conn_sd)
414{
415 /* Version handshake */
416 int rc = send(conn_sd, "RFB 003.008\n", 12, 0);
417 if (rc != EOK)
418 return;
419
420 char client_version[12];
421 rc = recv_chars(conn_sd, client_version, 12);
422 if (rc != EOK)
423 return;
424
425 if (memcmp(client_version, "RFB 003.008\n", 12) != 0)
426 return;
427
428 /* Security handshake
429 * 1 security type supported, which is 1 - None
430 */
431 char sec_types[2];
432 sec_types[0] = 1; /* length */
433 sec_types[1] = RFB_SECURITY_NONE;
434 rc = send(conn_sd, sec_types, 2, 0);
435 if (rc != EOK)
436 return;
437
438 char selected_sec_type = 0;
439 rc = recv_char(conn_sd, &selected_sec_type);
440 if (rc != EOK)
441 return;
442 if (selected_sec_type != RFB_SECURITY_NONE)
443 return;
444 uint32_t security_result = RFB_SECURITY_HANDSHAKE_OK;
445 rc = send(conn_sd, &security_result, sizeof(uint32_t), 0);
446 if (rc != EOK)
447 return;
448
449 /* Client init */
450 char shared_flag;
451 rc = recv_char(conn_sd, &shared_flag);
452 if (rc != EOK)
453 return;
454
455 /* Server init */
456 fibril_mutex_lock(&rfb->lock);
457 size_t name_length = str_length(rfb->name);
458 size_t msg_length = sizeof(rfb_server_init_t) + name_length;
459 rfb_server_init_t *server_init = malloc(msg_length);
460 if (server_init == NULL) {
461 fibril_mutex_unlock(&rfb->lock);
462 return;
463 }
464 server_init->width = rfb->width;
465 server_init->height = rfb->height;
466 server_init->pixel_format = rfb->pixel_format,
467 server_init->name_length = name_length;
468 rfb_server_init_to_be(server_init, server_init);
469 memcpy(server_init->name, rfb->name, name_length);
470 fibril_mutex_unlock(&rfb->lock);
471 rc = send(conn_sd, server_init, msg_length, 0);
472 if (rc != EOK)
473 return;
474
475 while (true) {
476 char message_type = 0;
477 rc = recv_char(conn_sd, &message_type);
478 if (rc != EOK)
479 return;
480
481 rfb_set_pixel_format_t spf;
482 rfb_set_encodings_t se;
483 rfb_framebuffer_update_request_t fbur;
484 rfb_key_event_t ke;
485 rfb_pointer_event_t pe;
486 rfb_client_cut_text_t cct;
487 switch (message_type) {
488 case RFB_CMSG_SET_PIXEL_FORMAT:
489 recv_message(conn_sd, message_type, &spf, sizeof(spf));
490 rfb_pixel_format_to_host(&spf.pixel_format, &spf.pixel_format);
491 fibril_mutex_lock(&rfb->lock);
492 rc = rfb_set_pixel_format(rfb, &spf.pixel_format);
493 fibril_mutex_unlock(&rfb->lock);
494 if (rc != EOK)
495 return;
496 printf("set pixel format\n");
497 break;
498 case RFB_CMSG_SET_ENCODINGS:
499 recv_message(conn_sd, message_type, &se, sizeof(se));
500 rfb_set_encodings_to_host(&se, &se);
501 for (uint16_t i = 0; i < se.count; i++) {
502 int32_t encoding = 0;
503 rc = recv_chars(conn_sd, (char *) &encoding, sizeof(int32_t));
504 if (rc != EOK)
505 return;
506 encoding = uint32_t_be2host(encoding);
507 }
508 printf("set encodings\n");
509 break;
510 case RFB_CMSG_FRAMEBUFFER_UPDATE_REQUEST:
511 recv_message(conn_sd, message_type, &fbur, sizeof(fbur));
512 rfb_framebuffer_update_request_to_host(&fbur, &fbur);
513 printf("framebuffer update request\n");
514 fibril_mutex_lock(&rfb->lock);
515 rfb_send_framebuffer_update(rfb, conn_sd, fbur.incremental);
516 fibril_mutex_unlock(&rfb->lock);
517 break;
518 case RFB_CMSG_KEY_EVENT:
519 recv_message(conn_sd, message_type, &ke, sizeof(ke));
520 rfb_key_event_to_host(&ke, &ke);
521 break;
522 case RFB_CMSG_POINTER_EVENT:
523 recv_message(conn_sd, message_type, &pe, sizeof(pe));
524 rfb_pointer_event_to_host(&pe, &pe);
525 break;
526 case RFB_CMSG_CLIENT_CUT_TEXT:
527 recv_message(conn_sd, message_type, &cct, sizeof(cct));
528 rfb_client_cut_text_to_host(&cct, &cct);
529 recv_skip_chars(conn_sd, cct.length);
530 break;
531 default:
532 return;
533 }
534 }
535}
536
537int rfb_listen(rfb_t *rfb, uint16_t port) {
538 struct sockaddr_in addr;
539
540 addr.sin_family = AF_INET;
541 addr.sin_port = htons(port);
542
543 int rc = inet_pton(AF_INET, "127.0.0.1", (void *)
544 &addr.sin_addr.s_addr);
545 if (rc != EOK) {
546 fprintf(stderr, "Error parsing network address (%s)\n",
547 str_error(rc));
548 return rc;
549 }
550
551 int listen_sd = socket(PF_INET, SOCK_STREAM, 0);
552 if (listen_sd < 0) {
553 fprintf(stderr, "Error creating listening socket (%s)\n",
554 str_error(listen_sd));
555 return rc;
556 }
557
558 rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
559 if (rc != EOK) {
560 fprintf(stderr, "Error binding socket (%s)\n",
561 str_error(rc));
562 return rc;
563 }
564
565 rc = listen(listen_sd, 2);
566 if (rc != EOK) {
567 fprintf(stderr, "listen() failed (%s)\n", str_error(rc));
568 return rc;
569 }
570
571 rfb->listen_sd = listen_sd;
572
573 return EOK;
574}
575
576void rfb_accept(rfb_t *rfb)
577{
578 while (true) {
579 struct sockaddr_in raddr;
580 socklen_t raddr_len = sizeof(raddr);
581 int conn_sd = accept(rfb->listen_sd, (struct sockaddr *) &raddr,
582 &raddr_len);
583
584 if (conn_sd < 0) {
585 fprintf(stderr, "accept() failed (%s)\n", str_error(conn_sd));
586 continue;
587 }
588
589 rbuf_out = 0;
590 rbuf_in = 0;
591
592 rfb_socket_connection(rfb, conn_sd);
593 closesocket(conn_sd);
594 }
595}
Note: See TracBrowser for help on using the repository browser.