source: mainline/uspace/srv/hid/rfb/rfb.c@ 3482bcc

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

rfb: Fix encoding of pixel values

  • Property mode set to 100644
File size: 12.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
38#include <net/in.h>
39#include <net/inet.h>
40#include <net/socket.h>
41
42#include "rfb.h"
43
44/** Buffer for receiving the request. */
45#define BUFFER_SIZE 1024
46
47static char rbuf[BUFFER_SIZE];
48static size_t rbuf_out;
49static size_t rbuf_in;
50
51
52/** Receive one character (with buffering) */
53static int recv_char(int fd, char *c)
54{
55 if (rbuf_out == rbuf_in) {
56 rbuf_out = 0;
57 rbuf_in = 0;
58
59 ssize_t rc = recv(fd, rbuf, BUFFER_SIZE, 0);
60 if (rc <= 0) {
61 fprintf(stderr, "recv() failed (%zd)\n", rc);
62 return rc;
63 }
64
65 rbuf_in = rc;
66 }
67
68 *c = rbuf[rbuf_out++];
69 return EOK;
70}
71
72/** Receive count characters (with buffering) */
73static int recv_chars(int fd, char *c, size_t count)
74{
75 for (size_t i = 0; i < count; i++) {
76 int rc = recv_char(fd, c);
77 if (rc != EOK)
78 return rc;
79 c++;
80 }
81 return EOK;
82}
83
84static int recv_skip_chars(int fd, size_t count)
85{
86 for (size_t i = 0; i < count; i++) {
87 char c;
88 int rc = recv_char(fd, &c);
89 if (rc != EOK)
90 return rc;
91 }
92 return EOK;
93}
94
95static void rfb_pixel_format_to_be(rfb_pixel_format_t *src, rfb_pixel_format_t *dst)
96{
97 dst->r_max = host2uint16_t_be(src->r_max);
98 dst->g_max = host2uint16_t_be(src->g_max);
99 dst->b_max = host2uint16_t_be(src->b_max);
100}
101
102static void rfb_pixel_format_to_host(rfb_pixel_format_t *src, rfb_pixel_format_t *dst)
103{
104 dst->r_max = uint16_t_be2host(src->r_max);
105 dst->g_max = uint16_t_be2host(src->g_max);
106 dst->b_max = uint16_t_be2host(src->b_max);
107}
108
109static void rfb_server_init_to_be(rfb_server_init_t *src, rfb_server_init_t *dst)
110{
111 dst->width = host2uint16_t_be(src->width);
112 dst->height = host2uint16_t_be(src->height);
113 rfb_pixel_format_to_be(&src->pixel_format, &dst->pixel_format);
114 dst->name_length = host2uint32_t_be(src->name_length);
115}
116
117static void rfb_set_encodings_to_host(rfb_set_encodings_t *src, rfb_set_encodings_t *dst)
118{
119 dst->count = uint16_t_be2host(src->count);
120}
121
122static void rfb_framebuffer_update_request_to_host(rfb_framebuffer_update_request_t *src,
123 rfb_framebuffer_update_request_t *dst)
124{
125 dst->x = uint16_t_be2host(src->x);
126 dst->y = uint16_t_be2host(src->x);
127 dst->width = uint16_t_be2host(src->width);
128 dst->height = uint16_t_be2host(src->height);
129}
130
131static void rfb_framebuffer_update_to_be(rfb_framebuffer_update_t *src,
132 rfb_framebuffer_update_t *dst)
133{
134 dst->rect_count = host2uint16_t_be(src->rect_count);
135}
136
137static void rfb_rectangle_to_be(rfb_rectangle_t *src, rfb_rectangle_t *dst)
138{
139 dst->x = host2uint16_t_be(src->x);
140 dst->y = host2uint16_t_be(src->y);
141 dst->width = host2uint16_t_be(src->width);
142 dst->height = host2uint16_t_be(src->height);
143 dst->enctype = host2uint32_t_be(src->enctype);
144}
145
146static void rfb_key_event_to_host(rfb_key_event_t *src, rfb_key_event_t *dst)
147{
148 dst->key = uint32_t_be2host(src->key);
149}
150
151static void rfb_pointer_event_to_host(rfb_pointer_event_t *src, rfb_pointer_event_t *dst)
152{
153 dst->x = uint16_t_be2host(src->x);
154 dst->y = uint16_t_be2host(src->y);
155}
156
157static void rfb_client_cut_text_to_host(rfb_client_cut_text_t *src,
158 rfb_client_cut_text_t *dst)
159{
160 dst->length = uint32_t_be2host(src->length);
161}
162
163int rfb_init(rfb_t *rfb, uint16_t width, uint16_t height)
164{
165 memset(rfb, 0, sizeof(rfb_t));
166 fibril_mutex_initialize(&rfb->lock);
167
168 rfb_pixel_format_t *pf = &rfb->pixel_format;
169 pf->bpp = 32;
170 pf->depth = 24;
171 pf->big_endian = 1;
172 pf->true_color = 1;
173 pf->r_max = 255;
174 pf->g_max = 255;
175 pf->b_max = 255;
176 pf->r_shift = 0;
177 pf->g_shift = 8;
178 pf->b_shift = 16;
179
180 rfb->name = "HelenOS";
181
182 return rfb_set_size(rfb, width, height);
183}
184
185int rfb_set_size(rfb_t *rfb, uint16_t width, uint16_t height)
186{
187 size_t new_size = width * height * sizeof(pixel_t);
188 void *pixbuf = malloc(new_size);
189 if (pixbuf == NULL)
190 return ENOMEM;
191
192 free(rfb->framebuffer.data);
193 rfb->framebuffer.data = pixbuf;
194 rfb->framebuffer.width = width;
195 rfb->framebuffer.height = height;
196 rfb->width = width;
197 rfb->height = height;
198
199 /* Fill with white */
200 memset(rfb->framebuffer.data, 255, new_size);
201
202 return EOK;
203}
204
205static int recv_message(int conn_sd, char type, void *buf, size_t size)
206{
207 memcpy(buf, &type, 1);
208 return recv_chars(conn_sd, ((char *) buf) + 1, size -1);
209}
210
211static uint32_t rfb_scale_channel(uint8_t val, uint32_t max)
212{
213 return val * max / 255;
214}
215
216static void rfb_encode_pixel(void *buf, rfb_pixel_format_t *pf, uint8_t r, uint8_t g,
217 uint8_t b)
218{
219 uint32_t pix = 0;
220 pix |= rfb_scale_channel(r, pf->r_max) << pf->r_shift;
221 pix |= rfb_scale_channel(g, pf->g_max) << pf->g_shift;
222 pix |= rfb_scale_channel(b, pf->b_max) << pf->b_shift;
223
224 if (pf->bpp == 8) {
225 uint8_t pix8 = pix;
226 memcpy(buf, &pix8, 1);
227 }
228 else if (pf->bpp == 16) {
229 uint16_t pix16 = pix;
230 if (pf->big_endian) {
231 pix16 = host2uint16_t_be(pix16);
232 }
233 else {
234 pix16 = host2uint16_t_le(pix16);
235 }
236 memcpy(buf, &pix16, 2);
237 }
238 else if (pf->bpp == 32) {
239 if (pf->big_endian) {
240 pix = host2uint32_t_be(pix);
241 }
242 else {
243 pix = host2uint32_t_le(pix);
244 }
245 memcpy(buf, &pix, 4);
246 }
247}
248
249static int rfb_send_framebuffer_update(rfb_t *rfb, int conn_sd, bool incremental)
250{
251 if (!incremental || !rfb->damage_valid) {
252 rfb->damage_rect.x = 0;
253 rfb->damage_rect.y = 0;
254 rfb->damage_rect.width = rfb->width;
255 rfb->damage_rect.height = rfb->height;
256 }
257
258
259 /* We send only single raw rectangle right now */
260 size_t buf_size = sizeof(rfb_framebuffer_update_t) +
261 sizeof(rfb_rectangle_t) * 1 +
262 (rfb->damage_rect.width * rfb->damage_rect.height * (rfb->pixel_format.bpp/8));
263
264 void *buf = malloc(buf_size);
265 if (buf == NULL)
266 return ENOMEM;
267 memset(buf, 0, buf_size);
268
269 void *pos = buf;
270 rfb_framebuffer_update_t *fbu = buf;
271 fbu->message_type = RFB_SMSG_FRAMEBUFFER_UPDATE;
272 fbu->rect_count = 1;
273 rfb_framebuffer_update_to_be(fbu, fbu);
274 pos += sizeof(rfb_framebuffer_update_t);
275
276 rfb_rectangle_t *rect = pos;
277 *rect = rfb->damage_rect;
278 rect->enctype = RFB_ENCODING_RAW;
279 rfb_rectangle_to_be(rect, rect);
280 pos += sizeof(rfb_rectangle_t);
281
282 size_t pixel_size = rfb->pixel_format.bpp / 8;
283
284 for (uint16_t y = 0; y < rfb->damage_rect.height; y++) {
285 for (uint16_t x = 0; x < rfb->damage_rect.width; x++) {
286 pixel_t pixel = pixelmap_get_pixel(&rfb->framebuffer,
287 x + rfb->damage_rect.x, y + rfb->damage_rect.y);
288 rfb_encode_pixel(pos, &rfb->pixel_format, RED(pixel), GREEN(pixel), BLUE(pixel));
289 pos += pixel_size;
290 }
291 }
292
293 int rc = send(conn_sd, buf, buf_size, 0);
294 free(buf);
295
296 rfb->damage_valid = false;
297 return rc;
298}
299
300static void rfb_socket_connection(rfb_t *rfb, int conn_sd)
301{
302 /* Version handshake */
303 int rc = send(conn_sd, "RFB 003.008\n", 12, 0);
304 if (rc != EOK)
305 return;
306
307 char client_version[12];
308 rc = recv_chars(conn_sd, client_version, 12);
309 if (rc != EOK)
310 return;
311
312 if (memcmp(client_version, "RFB 003.008\n", 12) != 0)
313 return;
314
315 /* Security handshake
316 * 1 security type supported, which is 1 - None
317 */
318 char sec_types[2];
319 sec_types[0] = 1; /* length */
320 sec_types[1] = RFB_SECURITY_NONE;
321 rc = send(conn_sd, sec_types, 2, 0);
322 if (rc != EOK)
323 return;
324
325 char selected_sec_type = 0;
326 rc = recv_char(conn_sd, &selected_sec_type);
327 if (rc != EOK)
328 return;
329 if (selected_sec_type != RFB_SECURITY_NONE)
330 return;
331 uint32_t security_result = RFB_SECURITY_HANDSHAKE_OK;
332 rc = send(conn_sd, &security_result, sizeof(uint32_t), 0);
333 if (rc != EOK)
334 return;
335
336 /* Client init */
337 char shared_flag;
338 rc = recv_char(conn_sd, &shared_flag);
339 if (rc != EOK)
340 return;
341
342 /* Server init */
343 fibril_mutex_lock(&rfb->lock);
344 size_t name_length = str_length(rfb->name);
345 size_t msg_length = sizeof(rfb_server_init_t) + name_length;
346 rfb_server_init_t *server_init = malloc(msg_length);
347 if (server_init == NULL) {
348 fibril_mutex_unlock(&rfb->lock);
349 return;
350 }
351 server_init->width = rfb->width;
352 server_init->height = rfb->height;
353 server_init->pixel_format = rfb->pixel_format,
354 server_init->name_length = name_length;
355 rfb_server_init_to_be(server_init, server_init);
356 memcpy(server_init->name, rfb->name, name_length);
357 fibril_mutex_unlock(&rfb->lock);
358 rc = send(conn_sd, server_init, msg_length, 0);
359 if (rc != EOK)
360 return;
361
362 while (true) {
363 char message_type = 0;
364 rc = recv_char(conn_sd, &message_type);
365 if (rc != EOK)
366 return;
367
368 rfb_set_pixel_format_t spf;
369 rfb_set_encodings_t se;
370 rfb_framebuffer_update_request_t fbur;
371 rfb_key_event_t ke;
372 rfb_pointer_event_t pe;
373 rfb_client_cut_text_t cct;
374 switch (message_type) {
375 case RFB_CMSG_SET_PIXEL_FORMAT:
376 recv_message(conn_sd, message_type, &spf, sizeof(spf));
377 rfb_pixel_format_to_host(&spf.pixel_format, &spf.pixel_format);
378 fibril_mutex_lock(&rfb->lock);
379 rfb->pixel_format = spf.pixel_format;
380 fibril_mutex_unlock(&rfb->lock);
381 printf("set pixel format\n");
382 break;
383 case RFB_CMSG_SET_ENCODINGS:
384 recv_message(conn_sd, message_type, &se, sizeof(se));
385 rfb_set_encodings_to_host(&se, &se);
386 for (uint16_t i = 0; i < se.count; i++) {
387 int32_t encoding = 0;
388 rc = recv_chars(conn_sd, (char *) &encoding, sizeof(int32_t));
389 if (rc != EOK)
390 return;
391 encoding = uint32_t_be2host(encoding);
392 }
393 printf("set encodings\n");
394 break;
395 case RFB_CMSG_FRAMEBUFFER_UPDATE_REQUEST:
396 recv_message(conn_sd, message_type, &fbur, sizeof(fbur));
397 rfb_framebuffer_update_request_to_host(&fbur, &fbur);
398 printf("framebuffer update request\n");
399 fibril_mutex_lock(&rfb->lock);
400 rfb_send_framebuffer_update(rfb, conn_sd, fbur.incremental);
401 fibril_mutex_unlock(&rfb->lock);
402 break;
403 case RFB_CMSG_KEY_EVENT:
404 recv_message(conn_sd, message_type, &ke, sizeof(ke));
405 rfb_key_event_to_host(&ke, &ke);
406 break;
407 case RFB_CMSG_POINTER_EVENT:
408 recv_message(conn_sd, message_type, &pe, sizeof(pe));
409 rfb_pointer_event_to_host(&pe, &pe);
410 break;
411 case RFB_CMSG_CLIENT_CUT_TEXT:
412 recv_message(conn_sd, message_type, &cct, sizeof(cct));
413 rfb_client_cut_text_to_host(&cct, &cct);
414 recv_skip_chars(conn_sd, cct.length);
415 break;
416 default:
417 return;
418 }
419 }
420}
421
422int rfb_listen(rfb_t *rfb, uint16_t port) {
423 struct sockaddr_in addr;
424
425 addr.sin_family = AF_INET;
426 addr.sin_port = htons(port);
427
428 int rc = inet_pton(AF_INET, "127.0.0.1", (void *)
429 &addr.sin_addr.s_addr);
430 if (rc != EOK) {
431 fprintf(stderr, "Error parsing network address (%s)\n",
432 str_error(rc));
433 return rc;
434 }
435
436 int listen_sd = socket(PF_INET, SOCK_STREAM, 0);
437 if (listen_sd < 0) {
438 fprintf(stderr, "Error creating listening socket (%s)\n",
439 str_error(listen_sd));
440 return rc;
441 }
442
443 rc = bind(listen_sd, (struct sockaddr *) &addr, sizeof(addr));
444 if (rc != EOK) {
445 fprintf(stderr, "Error binding socket (%s)\n",
446 str_error(rc));
447 return rc;
448 }
449
450 rc = listen(listen_sd, 2);
451 if (rc != EOK) {
452 fprintf(stderr, "listen() failed (%s)\n", str_error(rc));
453 return rc;
454 }
455
456 rfb->listen_sd = listen_sd;
457
458 return EOK;
459}
460
461void rfb_accept(rfb_t *rfb)
462{
463 while (true) {
464 struct sockaddr_in raddr;
465 socklen_t raddr_len = sizeof(raddr);
466 int conn_sd = accept(rfb->listen_sd, (struct sockaddr *) &raddr,
467 &raddr_len);
468
469 if (conn_sd < 0) {
470 fprintf(stderr, "accept() failed (%s)\n", str_error(conn_sd));
471 continue;
472 }
473
474 rbuf_out = 0;
475 rbuf_in = 0;
476
477 rfb_socket_connection(rfb, conn_sd);
478 closesocket(conn_sd);
479 }
480}
Note: See TracBrowser for help on using the repository browser.