6 #include "../aseg-paging/keyboard.h"
12 #define SET_PIXEL_FORMAT 0
13 #define SET_ENCODINGS 2
14 #define FB_UPDATE_REQUEST 3
16 #define POINTER_EVENT 5
17 #define CLIENT_CUT_TEXT 6
19 #define RFB_BUF_SIZE 64
21 #define SCREEN_CHUNKS_X 16
22 #define SCREEN_CHUNKS_Y 8
38 struct server_init_message {
41 struct pixel_format fmt;
46 struct fb_update_req {
62 struct key_event_pkt {
69 struct pointer_event_pkt {
76 struct text_event_pkt {
83 struct update_header {
103 char data[RFB_BUF_SIZE];
107 char next_update_incremental;
108 char update_requested;
110 struct fb_update_req client_interest_area;
118 uint32_t checksums[SCREEN_CHUNKS_Y][SCREEN_CHUNKS_X];
124 uint32_t chunk_width;
125 uint32_t chunk_height;
127 uint32_t chunk_lindex;
130 static struct server_init_message server_info;
132 static void init_server_info() {
133 server_info.name_length = htonl(8);
134 memcpy(server_info.name_string, "NetWatch", 8);
137 static void update_server_info() {
139 outputf("RFB: setting fmt %d", fb->curmode.format);
140 server_info.fb_width = htons(fb->curmode.xres);
141 server_info.fb_height = htons(fb->curmode.yres);
142 switch (fb->curmode.format) {
144 server_info.fmt.bpp = 32;
145 server_info.fmt.depth = 24;
146 server_info.fmt.big_endian = 0;
147 server_info.fmt.true_color = 1;
148 server_info.fmt.red_max = htons(255);
149 server_info.fmt.green_max = htons(255);
150 server_info.fmt.blue_max = htons(255);
151 server_info.fmt.red_shift = 0;
152 server_info.fmt.green_shift = 8;
153 server_info.fmt.blue_shift = 16;
156 outputf("RFB: unknown fb fmt %d", fb->curmode.format);
160 outputf("RFB: fb null");
164 static void send_fsm(struct tcp_pcb *pcb, struct rfb_state *state) {
165 struct update_header hdr;
171 switch (state->send_state) {
174 if (state->update_requested) {
175 outputf("RFB send: update requested");
176 state->update_requested = 0;
177 state->send_state = SST_NEEDS_UPDATE;
182 /* FALL THROUGH to SST_NEEDS_UPDATE */
184 case SST_NEEDS_UPDATE:
186 state->chunk_xnum = 0;
187 state->chunk_ynum = 0;
188 state->chunk_width = 0;
189 state->chunk_height = 0;
190 state->chunk_lindex = 0;
191 state->send_state = SST_SENDING;
193 /* FALL THROUGH to SST_SENDING */
198 lines_left = state->chunk_height - state->chunk_lindex;
200 if (lines_left == 0) {
201 outputf("RFB: (%d [%d], %d [%d]), advancing",
202 state->chunk_xnum, state->chunk_xpos,
203 state->chunk_ynum, state->chunk_ypos);
205 /* Advance to the next chunk if necessary. If
206 * state->chunk_height is zero, then we are
207 * arriving here for the first time from
208 * SST_NEEDS_UPDATE. */
210 if (state->chunk_height != 0) {
211 state->chunk_xnum += 1;
214 if (state->chunk_xnum == SCREEN_CHUNKS_X) {
215 state->chunk_ynum += 1;
216 state->chunk_xnum = 0;
219 if (state->chunk_ynum == SCREEN_CHUNKS_Y) {
220 state->send_state = SST_IDLE;
224 outputf("RFB send: sending header");
226 /* Calculate the width and height for this chunk, remembering
227 * that if SCREEN_CHUNKS_[XY] do not evenly divide the width and
228 * height, we may need to have shorter chunks at the edge of
231 state->chunk_width = fb->curmode.xres / SCREEN_CHUNKS_X;
232 if (fb->curmode.xres % SCREEN_CHUNKS_X != 0)
233 state->chunk_width += 1;
234 state->chunk_xpos = state->chunk_width * state->chunk_xnum;
235 totaldim = state->chunk_width * (state->chunk_xnum + 1);
236 if (totaldim > fb->curmode.xres) {
237 state->chunk_width -= (totaldim - fb->curmode.xres);
240 state->chunk_height = fb->curmode.yres / SCREEN_CHUNKS_Y;
241 if (fb->curmode.yres % SCREEN_CHUNKS_Y != 0)
242 state->chunk_height += 1;
243 state->chunk_ypos = state->chunk_height
245 totaldim = state->chunk_height * (state->chunk_ynum + 1);
246 if (totaldim > fb->curmode.yres) {
247 state->chunk_height -= (totaldim - fb->curmode.yres);
252 hdr.nrects = htons(1);
253 hdr.xpos = htons(state->chunk_xpos);
254 hdr.ypos = htons(state->chunk_ypos);
255 hdr.width = htons(state->chunk_width);
256 hdr.height= htons(state->chunk_height);
257 hdr.enctype = htonl(0);
258 state->chunk_lindex = 0;
259 lines_left = state->chunk_height;
261 err = tcp_write(pcb, &hdr, sizeof(hdr), TCP_WRITE_FLAG_COPY);
265 outputf("RFB: header send error %d", err);
267 /* Crap. Reset chunk_height to 0 so that next time around,
268 * we'll recalculate this chunk (not advance) and try to
269 * send the header again.
271 state->chunk_height = 0;
276 outputf("RFB: (%d [%d], %d [%d]), %d x %d, line %d",
277 state->chunk_xnum, state->chunk_xpos,
278 state->chunk_ynum, state->chunk_ypos,
279 state->chunk_width, state->chunk_height,
280 state->chunk_lindex);
283 + (fb->curmode.xres * fb->curmode.bytestride
284 * (state->chunk_ypos + state->chunk_lindex))
285 + (state->chunk_xpos * fb->curmode.bytestride);
287 /* The network card can't DMA from video RAM,
288 * so use TCP_WRITE_FLAG_COPY. */
289 err = tcp_write(pcb, lptr,
290 fb->curmode.bytestride * state->chunk_width,
291 TCP_WRITE_FLAG_COPY);
294 state->chunk_lindex += 1;
297 } while (err == ERR_OK && state->chunk_lindex < state->chunk_height);
301 outputf("RFB: send error %d", err);
303 outputf("RFB: that's all for now");
307 if (tcp_sndbuf(pcb) == 0) {
315 if (tcp_output(pcb) != ERR_OK)
316 outputf("RFB: tcp_output bailed in send_fsm?");
319 static err_t rfb_sent(void *arg, struct tcp_pcb *pcb, uint16_t len) {
320 struct rfb_state *state = arg;
321 send_fsm(pcb, state);
325 static void close_conn(struct tcp_pcb *pcb, struct rfb_state *state) {
339 static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) {
343 outputf("RFB FSM: st %d rp %d wp %d", state->state, state->readpos,
346 switch(state->state) {
348 if (state->writepos < 12) return NEEDMORE;
350 if (!strncmp(state->data, "RFB 003.003\n", 12)) {
352 } else if (!strncmp(state->data, "RFB 003.005\n", 12)) {
353 /* Spec states that "RFB 003.005", an incorrect value,
354 * should be treated by the server as 3.3. */
356 } else if (!strncmp(state->data, "RFB 003.007\n", 12)) {
358 } else if (!strncmp(state->data, "RFB 003.008\n", 12)) {
361 outputf("RFB: Negotiation fail");
365 outputf("RFB: Negotiated v3.%d", state->version);
367 state->readpos += 12;
368 state->state = ST_CLIENTINIT;
370 /* We support one security type, currently "none".
371 * Send that and SecurityResult. */
372 if (state->version >= 7) {
373 tcp_write(pcb, "\x01\x01\x00\x00\x00\x00", 6, 0);
375 tcp_write(pcb, "\x01\x00\x00\x00\x00", 5, 0);
383 if (state->version >= 7) {
384 /* Ignore the security type and ClientInit */
385 if (state->writepos < 2) return NEEDMORE;
388 /* Just ClientInit */
389 if (state->writepos < 1) return NEEDMORE;
393 state->state = ST_MAIN;
395 outputf("RFB: Sending server info", state->version);
396 tcp_write(pcb, &server_info, sizeof(server_info), TCP_WRITE_FLAG_COPY);
402 if (state->writepos < 1) return NEEDMORE;
404 outputf("RFB: cmd %d", state->data[0]);
405 switch (state->data[0]) {
407 case SET_PIXEL_FORMAT:
409 if (state->writepos < (sizeof(struct pixel_format) + 4))
411 outputf("RFB: SetPixelFormat");
413 struct pixel_format * new_fmt =
414 (struct pixel_format *)(&state->data[4]);
418 state->readpos += sizeof(struct pixel_format) + 4;
422 if (state->writepos < 4) return NEEDMORE;
424 struct set_encs_req * req = (struct set_encs_req *)state->data;
426 pktsize = sizeof(struct set_encs_req) + (4 * ntohs(req->num));
428 outputf("RFB: SetEncodings [%d]", ntohs(req->num));
429 if (state->writepos < pktsize) return NEEDMORE;
431 for (i = 0; i < ntohs(req->num); i++) {
432 outputf("RFB: Encoding: %d", ntohl(req->encodings[i]));
436 state->readpos += pktsize;
439 case FB_UPDATE_REQUEST:
440 if (state->writepos < sizeof(struct fb_update_req))
442 outputf("RFB: UpdateRequest");
444 state->update_requested = 1;
445 memcpy(&state->client_interest_area, state->data,
446 sizeof(struct fb_update_req));
448 state->readpos += sizeof(struct fb_update_req);
452 if (state->writepos < sizeof(struct key_event_pkt))
455 struct key_event_pkt * p = (struct key_event_pkt *)state->data;
457 outputf("RFB: Key: %d (%c)", htonl(p->keysym), (htonl(p->keysym) & 0xFF));
458 kbd_inject_keysym(htonl(p->keysym), p->downflag);
460 state->readpos += sizeof(struct key_event_pkt);
464 if (state->writepos < sizeof(struct pointer_event_pkt))
466 outputf("RFB: Pointer");
470 state->readpos += sizeof(struct pointer_event_pkt);
473 case CLIENT_CUT_TEXT:
474 if (state->writepos < sizeof(struct text_event_pkt))
476 outputf("RFB: Cut Text");
478 struct text_event_pkt * pkt =
479 (struct text_event_pkt *)state->data;
481 if (state->writepos < sizeof(struct text_event_pkt)
487 state->readpos += sizeof(struct text_event_pkt)
492 outputf("RFB: Bad command: %d", state->data[0]);
495 outputf("RFB: Bad state");
500 static err_t rfb_recv(void *arg, struct tcp_pcb *pcb,
501 struct pbuf *p, err_t err) {
502 struct rfb_state *state = arg;
507 outputf("RFB: recv err %d", err);
508 /* FIXME do something better here? */
513 outputf("RFB: Connection closed");
514 close_conn(pcb, state);
518 if (p->tot_len > (RFB_BUF_SIZE - state->writepos)) {
520 outputf("RFB: Overflow!");
521 close_conn(pcb, state);
525 outputf("RFB: Processing %d", p->tot_len);
526 pbuf_copy_partial(p, state->data + state->writepos, p->tot_len, 0);
527 state->writepos += p->tot_len;
529 tcp_recved(pcb, p->tot_len);
533 switch (recv_fsm(pcb, state)) {
535 outputf("RFB FSM: blocking");
540 outputf("RFB FSM: ok");
542 /* Kick off a send. */
543 if (state->send_state == SST_IDLE
544 && state->update_requested) {
545 send_fsm(pcb, state);
548 if (state->readpos == state->writepos) {
554 state->data + state->readpos,
555 state->writepos - state->readpos);
560 outputf("RFB: Protocol error");
561 close_conn(pcb, state);
567 static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
568 struct rfb_state *state;
570 LWIP_UNUSED_ARG(arg);
571 LWIP_UNUSED_ARG(err);
573 state = (struct rfb_state *)mem_malloc(sizeof(struct rfb_state));
575 state->state = ST_BEGIN;
578 state->update_requested = 0;
579 state->send_state = SST_IDLE;
581 /* XXX: update_server_info() should be called from the 64ms timer, and deal
582 * with screen resizes appropriately. */
583 update_server_info();
587 outputf("rfb_accept: out of memory\n");
592 tcp_recv(pcb, rfb_recv);
593 tcp_sent(pcb, rfb_sent);
595 tcp_err(pcb, rfb_err);
596 tcp_poll(pcb, rfb_poll, 2);
598 tcp_write(pcb, "RFB 003.008\n", 12, 0);
610 tcp_bind(pcb, IP_ADDR_ANY, RFB_PORT);
611 pcb = tcp_listen(pcb);
612 tcp_accept(pcb, rfb_accept);