]> Joshua Wise's Git repositories - netwatch.git/blame - net/rfb.c
Be a little bit quieter, and consequentially be a lot bit faster.
[netwatch.git] / net / rfb.c
CommitLineData
7da36fbd
JP
1#include <stdint.h>
2#include <minilib.h>
3#include <output.h>
4#include <fb.h>
5
6#include "lwip/tcp.h"
7
8#include "rfb.h"
9
10#define SET_PIXEL_FORMAT 0
11#define SET_ENCODINGS 2
12#define FB_UPDATE_REQUEST 3
13#define KEY_EVENT 4
14#define POINTER_EVENT 5
15#define CLIENT_CUT_TEXT 6
16
80726808 17#define RFB_BUF_SIZE 64
7da36fbd
JP
18
19struct pixel_format {
20 uint8_t bpp;
21 uint8_t depth;
22 uint8_t big_endian;
23 uint8_t true_color;
24 uint16_t red_max;
25 uint16_t green_max;
26 uint16_t blue_max;
27 uint8_t red_shift;
28 uint8_t green_shift;
29 uint8_t blue_shift;
30 uint8_t padding[3];
31};
32
33struct server_init_message {
34 uint16_t fb_width;
35 uint16_t fb_height;
36 struct pixel_format fmt;
37 uint32_t name_length;
38 char name_string[8];
39};
40
41struct fb_update_req {
42 uint8_t msgtype;
43 uint8_t incremental;
44 uint16_t xpos;
45 uint16_t ypos;
46 uint16_t width;
47 uint16_t height;
48};
49
50struct set_encs_req {
51 uint8_t msgtype;
52 uint8_t padding;
53 uint16_t num;
54 int32_t encodings[];
55};
56
57struct key_event_pkt {
58 uint8_t msgtype;
59 uint8_t downflag;
60 uint8_t pad[2];
61 uint32_t keysym;
62};
63
64struct pointer_event_pkt {
65 uint8_t msgtype;
66 uint8_t button_mask;
67 uint16_t x;
68 uint16_t y;
69};
70
71struct text_event_pkt {
72 uint8_t msgtype;
73 uint8_t padding[3];
74 uint32_t length;
75 char text[];
76};
77
8ceb0515
JP
78struct update_header {
79 uint8_t msgtype;
80 uint8_t padding;
81 uint16_t nrects;
82 uint16_t xpos;
83 uint16_t ypos;
84 uint16_t width;
85 uint16_t height;
86 int32_t enctype;
87};
88
7da36fbd
JP
89struct rfb_state {
90 enum {
91 ST_BEGIN,
92 ST_CLIENTINIT,
93 ST_MAIN
94 } state;
95 int version;
96 int encs_remaining;
97
98 char data[RFB_BUF_SIZE];
99 int readpos;
100 int writepos;
101
102 char next_update_incremental;
8ceb0515
JP
103 char update_requested;
104
7da36fbd
JP
105 struct fb_update_req client_interest_area;
106
8ceb0515
JP
107 enum {
108 SST_IDLE,
109 SST_NEEDS_UPDATE,
110 SST_SENDING
111 } send_state;
112
113 uint32_t update_pos;
114 uint32_t frame_bytes;
7da36fbd
JP
115};
116
117static struct server_init_message server_info;
118
119static void init_server_info() {
80726808 120 server_info.name_length = htonl(8);
7da36fbd
JP
121 memcpy(server_info.name_string, "NetWatch", 8);
122}
123
124static void update_server_info() {
125 if (fb != NULL) {
80726808
JP
126 outputf("RFB: setting fmt %d", fb->curmode.format);
127 server_info.fb_width = htons(fb->curmode.xres);
128 server_info.fb_height = htons(fb->curmode.yres);
7da36fbd
JP
129 switch (fb->curmode.format) {
130 case FB_RGB888:
131 server_info.fmt.bpp = 32;
132 server_info.fmt.depth = 24;
133 server_info.fmt.big_endian = 0;
134 server_info.fmt.true_color = 1;
80726808
JP
135 server_info.fmt.red_max = htons(255);
136 server_info.fmt.green_max = htons(255);
137 server_info.fmt.blue_max = htons(255);
7da36fbd
JP
138 server_info.fmt.red_shift = 0;
139 server_info.fmt.green_shift = 8;
140 server_info.fmt.blue_shift = 16;
141 break;
142 default:
143 outputf("RFB: unknown fb fmt %d", fb->curmode.format);
144 break;
145 }
80726808
JP
146 } else {
147 outputf("RFB: fb null");
7da36fbd
JP
148 }
149}
150
8ceb0515
JP
151static void send_fsm(struct tcp_pcb *pcb, struct rfb_state *state) {
152 struct update_header hdr;
153 int left, sndlength;
154 err_t err;
155
156 switch (state->send_state) {
157 case SST_IDLE:
158 /* Nothing to do */
159 if (state->update_requested) {
160 outputf("RFB send: update requested");
161 state->update_requested = 0;
162 state->send_state = SST_NEEDS_UPDATE;
163 } else {
164 break;
165 }
166
167 /* potential FALL THROUGH */
168
169 case SST_NEEDS_UPDATE:
170 outputf("RFB send: sending header");
171 /* Send a header */
bbfab433 172 state->frame_bytes = fb->curmode.xres * fb->curmode.yres * fb->curmode.bytestride;
8ceb0515
JP
173 hdr.msgtype = 0;
174 hdr.nrects = htons(1);
175 hdr.xpos = htons(0);
176 hdr.ypos = htons(0);
177 hdr.width = htons(fb->curmode.xres);
178 hdr.height = htons(fb->curmode.yres);
179 hdr.enctype = htonl(0);
075bbc71 180 tcp_write(pcb, &hdr, sizeof(hdr), TCP_WRITE_FLAG_COPY);
8ceb0515
JP
181
182 state->update_pos = 0;
183 state->send_state = SST_SENDING;
184
185 /* FALL THROUGH */
186
187 case SST_SENDING:
bbfab433 188 while (1) {
075bbc71
JW
189 unsigned char mbuf[8192 /* XXX magic */];
190
bbfab433 191 left = state->frame_bytes - state->update_pos;
8ceb0515 192
bbfab433
JP
193 if (left == 0) {
194 state->send_state = SST_IDLE;
195 break;
8ceb0515 196 }
075bbc71
JW
197
198 if (left > 8192)
199 left = 8192;
8ceb0515 200
03bcc4db 201 memcpy(mbuf, fb->fbaddr + state->update_pos, left); /* It's OK if it becomes smaller later. */
075bbc71 202
03bcc4db 203 sndlength = left;
bbfab433 204 do {
075bbc71 205 err = tcp_write(pcb, mbuf, sndlength, TCP_WRITE_FLAG_COPY /* This is my memory on the stack, thank you very much. */);
03bcc4db 206 if (err == ERR_MEM) /* Back down until lwip says we've got space. */
bbfab433 207 sndlength /= 2;
bbfab433
JP
208 } while (err == ERR_MEM && sndlength > 1);
209
03bcc4db
JW
210 if (err != ERR_OK) {
211 /* We'll just give up for now and come back when we have space later. */
212 //outputf("RFB: send error %d", err);
bbfab433
JP
213 break;
214 }
215
bbfab433
JP
216 state->update_pos += sndlength;
217
218 if (tcp_sndbuf(pcb) == 0) {
219 break;
220 }
8ceb0515
JP
221 }
222
223 break;
224 }
075bbc71
JW
225
226 if (tcp_output(pcb) != ERR_OK)
227 {
228 outputf("RFB: tcp_output bailed in send_fsm?");
229 }
8ceb0515
JP
230}
231
232static err_t rfb_sent(void *arg, struct tcp_pcb *pcb, uint16_t len) {
233 struct rfb_state *state = arg;
234 send_fsm(pcb, state);
235 return ERR_OK;
80726808
JP
236}
237
7da36fbd
JP
238static void close_conn(struct tcp_pcb *pcb, struct rfb_state *state) {
239 tcp_arg(pcb, NULL);
240 tcp_sent(pcb, NULL);
241 tcp_recv(pcb, NULL);
242 mem_free(state);
243 tcp_close(pcb);
244}
245
246enum fsm_result {
247 NEEDMORE,
248 OK,
249 FAIL
250};
251
252static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) {
80726808
JP
253 int i;
254 int pktsize;
255
256 outputf("RFB FSM: st %d rp %d wp %d", state->state, state->readpos,
257 state->writepos);
7da36fbd
JP
258
259 switch(state->state) {
260 case ST_BEGIN:
261 if (state->writepos < 12) return NEEDMORE;
262
263 if (!strncmp(state->data, "RFB 003.003\n", 12)) {
264 state->version = 3;
265 } else if (!strncmp(state->data, "RFB 003.005\n", 12)) {
266 /* Spec states that "RFB 003.005", an incorrect value,
267 * should be treated by the server as 3.3. */
268 state->version = 3;
269 } else if (!strncmp(state->data, "RFB 003.007\n", 12)) {
270 state->version = 7;
271 } else if (!strncmp(state->data, "RFB 003.008\n", 12)) {
272 state->version = 8;
273 } else {
274 outputf("RFB: Negotiation fail");
275 return FAIL;
276 }
277
278 outputf("RFB: Negotiated v3.%d", state->version);
279
280 state->readpos += 12;
281 state->state = ST_CLIENTINIT;
282
80726808
JP
283 /* We support one security type, currently "none".
284 * Send that and SecurityResult. */
7da36fbd 285 if (state->version >= 7) {
80726808 286 tcp_write(pcb, "\x01\x01\x00\x00\x00\x00", 6, 0);
7da36fbd 287 } else {
80726808 288 tcp_write(pcb, "\x01\x00\x00\x00\x00", 5, 0);
7da36fbd
JP
289 }
290
7da36fbd
JP
291 tcp_output(pcb);
292
293 return OK;
294
295 case ST_CLIENTINIT:
80726808
JP
296 if (state->version >= 7) {
297 /* Ignore the security type and ClientInit */
298 if (state->writepos < 2) return NEEDMORE;
299 state->readpos += 2;
300 } else {
301 /* Just ClientInit */
302 if (state->writepos < 1) return NEEDMORE;
303 state->readpos += 1;
304 }
305
7da36fbd
JP
306 state->state = ST_MAIN;
307
80726808 308 outputf("RFB: Sending server info", state->version);
075bbc71 309 tcp_write(pcb, &server_info, sizeof(server_info), TCP_WRITE_FLAG_COPY);
7da36fbd
JP
310 tcp_output(pcb);
311
312 return OK;
313
314 case ST_MAIN:
315 if (state->writepos < 1) return NEEDMORE;
316
80726808 317 outputf("RFB: cmd %d", state->data[0]);
7da36fbd
JP
318 switch (state->data[0]) {
319
320 case SET_PIXEL_FORMAT:
321 /* SetPixelFormat */
322 if (state->writepos < (sizeof(struct pixel_format) + 4))
323 return NEEDMORE;
80726808 324 outputf("RFB: SetPixelFormat");
7da36fbd
JP
325/*
326 struct pixel_format * new_fmt =
327 (struct pixel_format *)(&state->data[4]);
328*/
329 /* XXX ... */
330
331 state->readpos += sizeof(struct pixel_format) + 4;
332 return OK;
333
334 case SET_ENCODINGS:
335 if (state->writepos < 4) return NEEDMORE;
336
337 struct set_encs_req * req = (struct set_encs_req *)state->data;
338
80726808 339 pktsize = sizeof(struct set_encs_req) + (4 * ntohs(req->num));
7da36fbd 340
80726808
JP
341 outputf("RFB: SetEncodings [%d]", ntohs(req->num));
342 if (state->writepos < pktsize) return NEEDMORE;
343
344 for (i = 0; i < ntohs(req->num); i++) {
345 outputf("RFB: Encoding: %d", ntohl(req->encodings[i]));
346 /* XXX ... */
7da36fbd 347
80726808
JP
348 }
349
350 state->readpos += pktsize;
7da36fbd
JP
351 return OK;
352
353 case FB_UPDATE_REQUEST:
354 if (state->writepos < sizeof(struct fb_update_req))
355 return NEEDMORE;
80726808 356 outputf("RFB: UpdateRequest");
7da36fbd 357
8ceb0515 358 state->update_requested = 1;
7da36fbd
JP
359 memcpy(&state->client_interest_area, state->data,
360 sizeof(struct fb_update_req));
361
362 state->readpos += sizeof(struct fb_update_req);
363 return OK;
364
365 case KEY_EVENT:
366 if (state->writepos < sizeof(struct key_event_pkt))
367 return NEEDMORE;
80726808 368 outputf("RFB: Key");
7da36fbd
JP
369
370 /* XXX stub */
371
372 state->readpos += sizeof(struct key_event_pkt);
373 return OK;
374
375 case POINTER_EVENT:
376 if (state->writepos < sizeof(struct pointer_event_pkt))
377 return NEEDMORE;
80726808 378 outputf("RFB: Pointer");
7da36fbd
JP
379
380 /* XXX stub */
381
382 state->readpos += sizeof(struct pointer_event_pkt);
383 return OK;
384
385 case CLIENT_CUT_TEXT:
386 if (state->writepos < sizeof(struct text_event_pkt))
387 return NEEDMORE;
80726808 388 outputf("RFB: Cut Text");
7da36fbd
JP
389
390 struct text_event_pkt * pkt =
391 (struct text_event_pkt *)state->data;
392
393 if (state->writepos < sizeof(struct text_event_pkt)
394 + pkt->length)
395 return NEEDMORE;
396
397 /* XXX stub */
398
399 state->readpos += sizeof(struct text_event_pkt)
400 + pkt->length;
401 return OK;
402
403 default:
404 outputf("RFB: Bad command: %d", state->data[0]);
405 }
406 default:
407 outputf("RFB: Bad state");
408 return FAIL;
409 }
410}
411
412static err_t rfb_recv(void *arg, struct tcp_pcb *pcb,
413 struct pbuf *p, err_t err) {
414 struct rfb_state *state = arg;
415
416 if (state == NULL)
417
418 if (err != ERR_OK) {
419 outputf("RFB: recv err %d", err);
420 /* FIXME do something better here? */
421 return ERR_OK;
422 }
423
424 if (p == NULL) {
425 outputf("RFB: Connection closed");
426 close_conn(pcb, state);
427 return ERR_OK;
428 }
429
430 if (p->tot_len > (RFB_BUF_SIZE - state->writepos)) {
431 /* Overflow! */
432 outputf("RFB: Overflow!");
433 close_conn(pcb, state);
434 return ERR_OK;
435 }
436
437 outputf("RFB: Processing %d", p->tot_len);
438 pbuf_copy_partial(p, state->data + state->writepos, p->tot_len, 0);
80726808
JP
439 state->writepos += p->tot_len;
440
7da36fbd
JP
441 tcp_recved(pcb, p->tot_len);
442 pbuf_free(p);
443
444 while (1) {
445 switch (recv_fsm(pcb, state)) {
446 case NEEDMORE:
80726808 447 outputf("RFB FSM: blocking");
7da36fbd
JP
448 /* Need more data */
449 return ERR_OK;
450
451 case OK:
80726808
JP
452 outputf("RFB FSM: ok");
453
03bcc4db 454 /* Kick off a send. */
8ceb0515
JP
455 if (state->send_state == SST_IDLE
456 && state->update_requested) {
457 send_fsm(pcb, state);
80726808
JP
458 }
459
7da36fbd
JP
460 if (state->readpos == state->writepos) {
461 state->readpos = 0;
462 state->writepos = 0;
463 return ERR_OK;
464 } else {
465 memmove(state->data,
466 state->data + state->readpos,
467 state->writepos - state->readpos);
468 }
469 break;
470 case FAIL:
471 /* Shit */
472 outputf("RFB: Protocol error");
473 close_conn(pcb, state);
474 return ERR_OK;
475 }
476 }
477}
478
479static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
480 struct rfb_state *state;
481
482 LWIP_UNUSED_ARG(arg);
483 LWIP_UNUSED_ARG(err);
484
485 state = (struct rfb_state *)mem_malloc(sizeof(struct rfb_state));
486
80726808
JP
487 state->state = ST_BEGIN;
488 state->readpos = 0;
489 state->writepos = 0;
8ceb0515
JP
490 state->update_requested = 0;
491 state->send_state = SST_IDLE;
80726808 492
7da36fbd
JP
493 /* XXX: update_server_info() should be called from the 64ms timer, and deal
494 * with screen resizes appropriately. */
495 update_server_info();
496
497 if (!state)
498 {
499 outputf("rfb_accept: out of memory\n");
500 return ERR_MEM;
501 }
502
503 tcp_arg(pcb, state);
504 tcp_recv(pcb, rfb_recv);
8ceb0515 505 tcp_sent(pcb, rfb_sent);
7da36fbd
JP
506/*
507 tcp_err(pcb, rfb_err);
508 tcp_poll(pcb, rfb_poll, 2);
509*/
510 tcp_write(pcb, "RFB 003.008\n", 12, 0);
511 tcp_output(pcb);
512
513 return ERR_OK;
514}
515
516void rfb_init() {
517 struct tcp_pcb *pcb;
518
519 init_server_info();
520
521 pcb = tcp_new();
522 tcp_bind(pcb, IP_ADDR_ANY, RFB_PORT);
523 pcb = tcp_listen(pcb);
524 tcp_accept(pcb, rfb_accept);
525}
This page took 0.069669 seconds and 4 git commands to generate.