]> Joshua Wise's Git repositories - netwatch.git/blame - net/rfb.c
a little more detail in rfb key logging
[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
ec949d20
JP
6#include "../aseg-paging/keyboard.h"
7
7da36fbd
JP
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
80726808 19#define RFB_BUF_SIZE 64
7da36fbd
JP
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
8ceb0515
JP
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
7da36fbd
JP
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;
8ceb0515
JP
105 char update_requested;
106
7da36fbd
JP
107 struct fb_update_req client_interest_area;
108
8ceb0515
JP
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;
7da36fbd
JP
117};
118
119static struct server_init_message server_info;
120
121static void init_server_info() {
80726808 122 server_info.name_length = htonl(8);
7da36fbd
JP
123 memcpy(server_info.name_string, "NetWatch", 8);
124}
125
126static void update_server_info() {
127 if (fb != NULL) {
80726808
JP
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);
7da36fbd
JP
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;
80726808
JP
137 server_info.fmt.red_max = htons(255);
138 server_info.fmt.green_max = htons(255);
139 server_info.fmt.blue_max = htons(255);
7da36fbd
JP
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 }
80726808
JP
148 } else {
149 outputf("RFB: fb null");
7da36fbd
JP
150 }
151}
152
8ceb0515
JP
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
8cc40c4d 169 /* FALL THROUGH to SST_NEEDS_UPDATE*/
8ceb0515
JP
170 case SST_NEEDS_UPDATE:
171 outputf("RFB send: sending header");
172 /* Send a header */
bbfab433 173 state->frame_bytes = fb->curmode.xres * fb->curmode.yres * fb->curmode.bytestride;
8ceb0515
JP
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);
075bbc71 181 tcp_write(pcb, &hdr, sizeof(hdr), TCP_WRITE_FLAG_COPY);
8ceb0515
JP
182
183 state->update_pos = 0;
184 state->send_state = SST_SENDING;
185
8cc40c4d 186 /* FALL THROUGH to SST_SENDING*/
8ceb0515 187 case SST_SENDING:
bbfab433
JP
188 while (1) {
189 left = state->frame_bytes - state->update_pos;
8ceb0515 190
bbfab433
JP
191 if (left == 0) {
192 state->send_state = SST_IDLE;
193 break;
8ceb0515 194 }
075bbc71 195
8cc40c4d 196 if (left > 8192) /* Sounds good enough to me. */
075bbc71 197 left = 8192;
8ceb0515 198
03bcc4db 199 sndlength = left;
bbfab433 200 do {
8cc40c4d 201 err = tcp_write(pcb, fb->fbaddr + state->update_pos, sndlength, TCP_WRITE_FLAG_COPY /* The card can't DMA from there. */);
03bcc4db 202 if (err == ERR_MEM) /* Back down until lwip says we've got space. */
bbfab433 203 sndlength /= 2;
bbfab433
JP
204 } while (err == ERR_MEM && sndlength > 1);
205
03bcc4db 206 if (err != ERR_OK) {
8cc40c4d
JW
207 if (err != ERR_MEM)
208 outputf("RFB: send error %d", err);
209
03bcc4db 210 /* We'll just give up for now and come back when we have space later. */
bbfab433
JP
211 break;
212 }
213
bbfab433
JP
214 state->update_pos += sndlength;
215
216 if (tcp_sndbuf(pcb) == 0) {
217 break;
218 }
8ceb0515
JP
219 }
220
221 break;
222 }
075bbc71
JW
223
224 if (tcp_output(pcb) != ERR_OK)
075bbc71 225 outputf("RFB: tcp_output bailed in send_fsm?");
8ceb0515
JP
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;
80726808
JP
232}
233
7da36fbd
JP
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) {
80726808
JP
249 int i;
250 int pktsize;
251
252 outputf("RFB FSM: st %d rp %d wp %d", state->state, state->readpos,
253 state->writepos);
7da36fbd
JP
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
80726808
JP
279 /* We support one security type, currently "none".
280 * Send that and SecurityResult. */
7da36fbd 281 if (state->version >= 7) {
80726808 282 tcp_write(pcb, "\x01\x01\x00\x00\x00\x00", 6, 0);
7da36fbd 283 } else {
80726808 284 tcp_write(pcb, "\x01\x00\x00\x00\x00", 5, 0);
7da36fbd
JP
285 }
286
7da36fbd
JP
287 tcp_output(pcb);
288
289 return OK;
290
291 case ST_CLIENTINIT:
80726808
JP
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
7da36fbd
JP
302 state->state = ST_MAIN;
303
80726808 304 outputf("RFB: Sending server info", state->version);
075bbc71 305 tcp_write(pcb, &server_info, sizeof(server_info), TCP_WRITE_FLAG_COPY);
7da36fbd
JP
306 tcp_output(pcb);
307
308 return OK;
309
310 case ST_MAIN:
311 if (state->writepos < 1) return NEEDMORE;
312
80726808 313 outputf("RFB: cmd %d", state->data[0]);
7da36fbd
JP
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;
80726808 320 outputf("RFB: SetPixelFormat");
7da36fbd
JP
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
80726808 335 pktsize = sizeof(struct set_encs_req) + (4 * ntohs(req->num));
7da36fbd 336
80726808
JP
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 ... */
80726808
JP
343 }
344
345 state->readpos += pktsize;
7da36fbd
JP
346 return OK;
347
348 case FB_UPDATE_REQUEST:
349 if (state->writepos < sizeof(struct fb_update_req))
350 return NEEDMORE;
80726808 351 outputf("RFB: UpdateRequest");
7da36fbd 352
8ceb0515 353 state->update_requested = 1;
7da36fbd
JP
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
ec949d20 364 struct key_event_pkt * p = (struct key_event_pkt *)state->data;
dadcd4fc
JP
365
366 outputf("RFB: Key: %d (%c)", htonl(p->keysym), (htonl(p->keysym) & 0xFF));
ec949d20 367 kbd_inject_keysym(htonl(p->keysym), p->downflag);
7da36fbd
JP
368
369 state->readpos += sizeof(struct key_event_pkt);
370 return OK;
371
372 case POINTER_EVENT:
373 if (state->writepos < sizeof(struct pointer_event_pkt))
374 return NEEDMORE;
80726808 375 outputf("RFB: Pointer");
7da36fbd
JP
376
377 /* XXX stub */
378
379 state->readpos += sizeof(struct pointer_event_pkt);
380 return OK;
381
382 case CLIENT_CUT_TEXT:
383 if (state->writepos < sizeof(struct text_event_pkt))
384 return NEEDMORE;
80726808 385 outputf("RFB: Cut Text");
7da36fbd
JP
386
387 struct text_event_pkt * pkt =
388 (struct text_event_pkt *)state->data;
389
390 if (state->writepos < sizeof(struct text_event_pkt)
391 + pkt->length)
392 return NEEDMORE;
393
394 /* XXX stub */
395
396 state->readpos += sizeof(struct text_event_pkt)
397 + pkt->length;
398 return OK;
399
400 default:
401 outputf("RFB: Bad command: %d", state->data[0]);
402 }
403 default:
404 outputf("RFB: Bad state");
405 return FAIL;
406 }
407}
408
409static err_t rfb_recv(void *arg, struct tcp_pcb *pcb,
410 struct pbuf *p, err_t err) {
411 struct rfb_state *state = arg;
412
413 if (state == NULL)
414
415 if (err != ERR_OK) {
416 outputf("RFB: recv err %d", err);
417 /* FIXME do something better here? */
418 return ERR_OK;
419 }
420
421 if (p == NULL) {
422 outputf("RFB: Connection closed");
423 close_conn(pcb, state);
424 return ERR_OK;
425 }
426
427 if (p->tot_len > (RFB_BUF_SIZE - state->writepos)) {
428 /* Overflow! */
429 outputf("RFB: Overflow!");
430 close_conn(pcb, state);
431 return ERR_OK;
432 }
433
434 outputf("RFB: Processing %d", p->tot_len);
435 pbuf_copy_partial(p, state->data + state->writepos, p->tot_len, 0);
80726808
JP
436 state->writepos += p->tot_len;
437
7da36fbd
JP
438 tcp_recved(pcb, p->tot_len);
439 pbuf_free(p);
440
441 while (1) {
442 switch (recv_fsm(pcb, state)) {
443 case NEEDMORE:
80726808 444 outputf("RFB FSM: blocking");
7da36fbd
JP
445 /* Need more data */
446 return ERR_OK;
447
448 case OK:
80726808
JP
449 outputf("RFB FSM: ok");
450
03bcc4db 451 /* Kick off a send. */
8ceb0515
JP
452 if (state->send_state == SST_IDLE
453 && state->update_requested) {
454 send_fsm(pcb, state);
80726808
JP
455 }
456
7da36fbd
JP
457 if (state->readpos == state->writepos) {
458 state->readpos = 0;
459 state->writepos = 0;
460 return ERR_OK;
461 } else {
462 memmove(state->data,
463 state->data + state->readpos,
464 state->writepos - state->readpos);
465 }
466 break;
467 case FAIL:
468 /* Shit */
469 outputf("RFB: Protocol error");
470 close_conn(pcb, state);
471 return ERR_OK;
472 }
473 }
474}
475
476static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
477 struct rfb_state *state;
478
479 LWIP_UNUSED_ARG(arg);
480 LWIP_UNUSED_ARG(err);
481
482 state = (struct rfb_state *)mem_malloc(sizeof(struct rfb_state));
483
80726808
JP
484 state->state = ST_BEGIN;
485 state->readpos = 0;
486 state->writepos = 0;
8ceb0515
JP
487 state->update_requested = 0;
488 state->send_state = SST_IDLE;
80726808 489
7da36fbd
JP
490 /* XXX: update_server_info() should be called from the 64ms timer, and deal
491 * with screen resizes appropriately. */
492 update_server_info();
493
494 if (!state)
495 {
496 outputf("rfb_accept: out of memory\n");
497 return ERR_MEM;
498 }
499
500 tcp_arg(pcb, state);
501 tcp_recv(pcb, rfb_recv);
8ceb0515 502 tcp_sent(pcb, rfb_sent);
7da36fbd
JP
503/*
504 tcp_err(pcb, rfb_err);
505 tcp_poll(pcb, rfb_poll, 2);
506*/
507 tcp_write(pcb, "RFB 003.008\n", 12, 0);
508 tcp_output(pcb);
509
510 return ERR_OK;
511}
512
513void rfb_init() {
514 struct tcp_pcb *pcb;
515
516 init_server_info();
517
518 pcb = tcp_new();
519 tcp_bind(pcb, IP_ADDR_ANY, RFB_PORT);
520 pcb = tcp_listen(pcb);
521 tcp_accept(pcb, rfb_accept);
522}
This page took 0.070834 seconds and 4 git commands to generate.