blob: 62a468092e29eebf18b82232d7ceb1f460226b64 [file] [log] [blame]
adamdunkels2d015312003-07-02 21:34:00 +00001/*
2 * Copyright (c) 2001, Adam Dunkels.
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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
adamdunkels9b852592004-06-06 05:54:47 +000013 * 3. The name of the author may not be used to endorse or promote
adamdunkels2d015312003-07-02 21:34:00 +000014 * products derived from this software without specific prior
15 * written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * This file is part of the uIP TCP/IP stack.
30 *
adamdunkels18c26e12004-08-09 20:32:28 +000031 * $Id: vnc-server.c,v 1.4 2004/08/09 20:32:28 adamdunkels Exp $
adamdunkels2d015312003-07-02 21:34:00 +000032 *
33 */
34
35/* A micro implementation of a VNC server. VNC is a protocol for
36 remote network displays. See http://www.uk.research.att.com/vnc/
37 for information about VNC.
38
39 Initialization states:
40
41 VNC_VERSION (send version string)
42 VNC_AUTH (send auth message)
43 VNC_INIT (send init message)
44
45 Steady state:
46
47 VNC_RUNNING (send RFB updates, parse incoming messages)
48
49 What kind of message should be sent:
50
51 SEND_NONE (No message)
52 SEND_BLANK (Blank screen initially)
53 SEND_SCREEN (Send entire screen, initially)
54 SEND_UPDATE (Send incremental update)
55
56*/
57
58#include "uip.h"
59#include "vnc-server.h"
60#include "vnc-out.h"
61
adamdunkels9b852592004-06-06 05:54:47 +000062#include <string.h>
adamdunkels2d015312003-07-02 21:34:00 +000063
64/* RFB server initial handshaking string. */
65#define RFB_SERVER_VERSION_STRING rfb_server_version_string
66
67/* "RFB 003.003" */
68static u8_t rfb_server_version_string[12] = {82,70,66,32,48,48,51,46,48,48,51,10};
69
70/* uVNC */
71static u8_t uvnc_name[4] = {117,86,78,67};
72#if 1
73#define PRINTF(x)
74#else
75#define PRINTF(x) printf x
76#endif
77
78/*-----------------------------------------------------------------------------------*/
79u8_t
80vnc_server_draw_rect(u8_t *ptr, u16_t x, u16_t y, u16_t w, u16_t h, u8_t c)
81{
adamdunkels18c26e12004-08-09 20:32:28 +000082 register struct rfb_fb_update_rect_hdr *recthdr;
adamdunkels2d015312003-07-02 21:34:00 +000083 struct rfb_rre_hdr *rrehdr;
84
85 recthdr = (struct rfb_fb_update_rect_hdr *)ptr;
86 rrehdr = (struct rfb_rre_hdr *)(ptr + sizeof(struct rfb_fb_update_rect_hdr));
87
88 recthdr->rect.x = x;
89 recthdr->rect.y = y;
90 recthdr->rect.w = w;
91 recthdr->rect.h = h;
92 recthdr->encoding[0] =
93 recthdr->encoding[1] =
94 recthdr->encoding[2] = 0;
95 recthdr->encoding[3] = RFB_ENC_RRE;
96
97 rrehdr->subrects[0] =
98 rrehdr->subrects[1] = 0;
99 rrehdr->bgpixel = c;
100
101 return sizeof(struct rfb_fb_update_rect_hdr) + sizeof(struct rfb_rre_hdr);
102}
103/*-----------------------------------------------------------------------------------*/
104void
105vnc_server_init(void)
106{
107 vnc_out_init();
108}
109/*-----------------------------------------------------------------------------------*/
110static void
111vnc_send_blank(struct vnc_server_state *vs)
112{
113 switch(vs->type) {
114 case 0:
115 vnc_out_send_blank(vs);
116 break;
117 /* case 1:
118 vnc_stats_send_blank(vs);
119 break; */
120 }
121}
122/*-----------------------------------------------------------------------------------*/
123static void
124vnc_send_screen(struct vnc_server_state *vs)
125{
126 switch(vs->type) {
127 case 0:
128 vnc_out_send_screen(vs);
129 break;
130 /* case 1:
131 vnc_stats_send_screen(vs);
132 break;*/
133 }
134}
135/*-----------------------------------------------------------------------------------*/
136static void
137vnc_send_update(struct vnc_server_state *vs)
138{
139 switch(vs->type) {
140 case 0:
141 vnc_out_send_update(vs);
142 break;
143 /* case 1:
144 vnc_stats_send_update(vs);
145 break;*/
146 }
147}
148/*-----------------------------------------------------------------------------------*/
149void
150vnc_server_send_data(struct vnc_server_state *vs)
151{
adamdunkels18c26e12004-08-09 20:32:28 +0000152 register struct rfb_server_init *initmsg;
adamdunkels2d015312003-07-02 21:34:00 +0000153
154 switch(vs->state) {
155 case VNC_VERSION:
156 uip_send(RFB_SERVER_VERSION_STRING, sizeof(RFB_SERVER_VERSION_STRING));
157 break;
158 case VNC_AUTH:
159 uip_appdata[0] = 0;
160 uip_appdata[1] = 0;
161 uip_appdata[2] = 0;
162 uip_appdata[3] = RFB_AUTH_NONE;
163 uip_send(uip_appdata, 4);
164 break;
165 case VNC_INIT:
166 initmsg = (struct rfb_server_init *)uip_appdata;
167 initmsg->width = htons(vs->width);
168 initmsg->height = htons(vs->height);
169 /* BGR233 pixel format. */
170 initmsg->format.bps = 8;
171 initmsg->format.depth = 8;
172 initmsg->format.endian = 1;
173 initmsg->format.truecolor = 1;
174 initmsg->format.red_max = htons(7);
175 initmsg->format.green_max = htons(7);
176 initmsg->format.blue_max = htons(3);
177 initmsg->format.red_shift = 0;
178 initmsg->format.green_shift = 3;
179 initmsg->format.blue_shift = 6;
180 initmsg->namelength[0] = 0;
181 initmsg->namelength[1] = 0;
182 initmsg->namelength[2] = 0;
183 initmsg->namelength[3] = 4;
adamdunkels9b852592004-06-06 05:54:47 +0000184 memcpy(&uip_appdata[sizeof(struct rfb_server_init)], uvnc_name, 4);
adamdunkels8bb5cca2003-08-24 22:41:31 +0000185 /* uip_appdata[sizeof(struct rfb_server_init)+0] = 'u';
adamdunkels2d015312003-07-02 21:34:00 +0000186 uip_appdata[sizeof(struct rfb_server_init)+1] = 'V';
187 uip_appdata[sizeof(struct rfb_server_init)+2] = 'N';
adamdunkels8bb5cca2003-08-24 22:41:31 +0000188 uip_appdata[sizeof(struct rfb_server_init)+3] = 'C';*/
adamdunkels2d015312003-07-02 21:34:00 +0000189 uip_send(uip_appdata, sizeof(struct rfb_server_init) + 4);
190 break;
191 case VNC_RUNNING:
192 switch(vs->sendmsg) {
193 case SEND_NONE:
194 PRINTF(("Sending none\n"));
195 break;
196
197 case SEND_BLANK:
198 case SENT_BLANK:
199 PRINTF(("Sending blank\n"));
200 vnc_send_blank(vs);
201 break;
202
203 case SEND_SCREEN:
204 PRINTF(("Sending screen\n"));
205 vnc_send_screen(vs);
206 break;
207
208 case SEND_UPDATE:
209 PRINTF(("Sending update\n"));
210 vnc_send_update(vs);
211 break;
212 }
213 break;
214
215 default:
216 break;
217 }
218
219}
220/*-----------------------------------------------------------------------------------*/
221static void
222vnc_key_event(struct vnc_server_state *vs)
223{
224 switch(vs->type) {
225 case 0:
226 vnc_out_key_event(vs);
227 break;
228 /* case 1:
229 vnc_stats_key_event(vs);
230 break;*/
231 }
232}
233/*-----------------------------------------------------------------------------------*/
234static void
235vnc_pointer_event(struct vnc_server_state *vs)
236{
237 switch(vs->type) {
238 case 0:
239 vnc_out_pointer_event(vs);
240 break;
241 /* case 1:
242 vnc_stats_pointer_event(vs);
243 break;*/
244 }
245}
246/*-----------------------------------------------------------------------------------*/
247static u8_t
adamdunkels18c26e12004-08-09 20:32:28 +0000248vnc_read_data(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000249{
250 u8_t *appdata;
251 u16_t len;
252 struct rfb_fb_update_request *req;
253 /* u8_t niter;*/
254
255 len = uip_datalen();
256 appdata = (u8_t *)uip_appdata;
257
258 /* First, check if there is data left to discard since last read. */
259 if(vs->readlen > 0) {
260 appdata += vs->readlen;
261 if(len > vs->readlen) {
262 len -= vs->readlen;
263 vs->readlen = 0;
264 } else {
265 vs->readlen -= len;
266 len = 0;
267 }
268 }
269
270 if(vs->readlen != 0) {
271 return 1;
272 }
273
274 /* All data read and ignored, parse next message. */
275 /* for(niter = 32; niter > 0 && len > 0; --niter) {*/
276 while(len > 0) {
277 switch(vs->state) {
278 case VNC_VERSION:
279 case VNC_VERSION2:
280 PRINTF(("Read in version\n"));
281 /* Receive and ignore client version string (12 bytes). */
282 vs->state = VNC_AUTH;
283 vs->readlen = 12;
284 break;
285
286 case VNC_AUTH:
287 case VNC_AUTH2:
288 PRINTF(("Read in auth \n"));
289 /* Read and discard initialization from client (1 byte). */
290 vs->readlen = 1;
291 vs->state = VNC_INIT;
292 break;
293
294 case VNC_INIT:
295 case VNC_INIT2:
296 PRINTF(("Read in init \n"));
297 vs->readlen = 0;
298 vs->state = VNC_RUNNING;
299
300 case VNC_RUNNING:
301 /* Handle all client events. */
302 switch(*appdata) {
303 case RFB_SET_PIXEL_FORMAT:
304 PRINTF(("Set pixel format\n"));
305 vs->readlen = sizeof(struct rfb_set_pixel_format);
306 /* Check if client runs with BGR233 format. If not, abort the
307 connection. */
308 /* XXX: not implemented yet. */
309 break;
310
311 case RFB_FIX_COLORMAP_ENTRIES:
312 PRINTF(("Fix colormap entries\n"));
313 return 0;
314
315 case RFB_SET_ENCODINGS:
316 PRINTF(("Set encodings\n"));
317 vs->readlen = sizeof(struct rfb_set_encoding);
318 vs->readlen += htons(((struct rfb_set_encoding *)appdata)->encodings) * 4;
319 /* Make sure that client supports the encodings we use. */
320 /* XXX: not implemented yet. */
321 break;
322
323 case RFB_FB_UPDATE_REQ:
324 PRINTF(("Update request\n"));
325 vs->update_requested = 1;
326 vs->readlen = sizeof(struct rfb_fb_update_request);
327 /* blank the screen initially */
328 req = (struct rfb_fb_update_request *)appdata;
329 if(req->incremental == 0) {
330 /* vs->sendmsg = SEND_BLANK;*/
331 vnc_out_update_area(vs, 0, 0, vs->w, vs->h);
332 }
333 break;
334
335 case RFB_KEY_EVENT:
336 vs->readlen = sizeof(struct rfb_key_event);
337 vnc_key_event(vs);
338 break;
339
340 case RFB_POINTER_EVENT:
341 vs->readlen = sizeof(struct rfb_pointer_event);
342 vnc_pointer_event(vs);
343 break;
344
345 case RFB_CLIENT_CUT_TEXT:
346 PRINTF(("Client cut text\n"));
347
348 if(((struct rfb_client_cut_text *)appdata)->len[0] != 0 ||
349 ((struct rfb_client_cut_text *)appdata)->len[1] != 0) {
350 return 0;
351
352 }
353 vs->readlen = sizeof(struct rfb_client_cut_text) +
354 (((struct rfb_client_cut_text *)appdata)->len[2] << 8) +
355 ((struct rfb_client_cut_text *)appdata)->len[3];
356 /* return 0;*/
357 break;
358
359 default:
360 PRINTF(("Unknown message %d\n", *appdata));
361 return 0;
362 }
363 break;
364
365 default:
366 return 0;
367 }
368
369 if(vs->readlen > 0) {
370 if(len > vs->readlen) {
371 len -= vs->readlen;
372 appdata += vs->readlen;
373 vs->readlen = 0;
374 } else {
375 vs->readlen -= len;
376 len = 0;
377 }
378 } else {
379 /* Lost data. */
380 break;
381 }
382
383 }
384
385 /* if(vs->readlen > 0) {
386 printf("More data %d\n", vs->readlen);
387 }*/
388
389 /* uip_appdata = appdata;*/
390
391 return 1;
392}
393/*-----------------------------------------------------------------------------------*/
394static void
adamdunkels18c26e12004-08-09 20:32:28 +0000395vnc_new(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000396{
397 vs->counter = 0;
398 vs->readlen = 0;
399 vs->sendmsg = SEND_NONE;
400 vs->update_requested = 1;
401 switch(vs->type) {
402 case 0:
403 vnc_out_new(vs);
404 break;
405 /* case 1:
406 vnc_stats_new(vs);
407 break;*/
408 }
409}
410/*-----------------------------------------------------------------------------------*/
411static void
adamdunkels18c26e12004-08-09 20:32:28 +0000412vnc_acked(register struct vnc_server_state *vs)
adamdunkels2d015312003-07-02 21:34:00 +0000413{
414 switch(vs->state) {
415 case VNC_VERSION:
416 vs->state = VNC_VERSION2;
417 break;
418
419 case VNC_AUTH:
420 vs->state = VNC_AUTH2;
421 break;
422
423 case VNC_INIT:
424 vs->state = VNC_INIT2;
425 break;
426
427 case VNC_RUNNING:
428 switch(vs->type) {
429 case 0:
430 vnc_out_acked(vs);
431 break;
432 /* case 1:
433 vnc_stats_acked(vs);
434 break;*/
435 }
436 break;
437 }
438}
439/*-----------------------------------------------------------------------------------*/
440void
441vnc_server_appcall(struct vnc_server_state *vs)
442{
443
444 vs->type = htons(uip_conn->lport) - 5900;
445
446 if(uip_connected()) {
447 vnc_new(vs);
448 vs->state = VNC_VERSION;
449 vnc_server_send_data(vs);
450 return;
451 }
452 if(uip_acked()) {
453 PRINTF(("Acked\n"));
454 vnc_acked(vs);
455 }
456
457 if(uip_newdata()) {
458 PRINTF(("Newdata\n"));
459 vs->counter = 0;
460 if(vnc_read_data(vs) == 0) {
461 uip_abort();
462 return;
463 }
464 }
465
466 if(uip_rexmit()) {
467 PRINTF(("Rexmit\n"));
468 }
469
470
471 if(uip_newdata() ||
472 uip_rexmit() ||
473 uip_acked()) {
474 vnc_server_send_data(vs);
475 } else if(uip_poll()) {
476 ++vs->counter;
477 /* Abort connection after about 20 seconds of inactivity. */
478 if(vs->counter >= 40) {
479 uip_abort();
480 return;
481 }
482
483 vnc_out_poll(vs);
484 }
485
486}
487/*-----------------------------------------------------------------------------------*/