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