X-Git-Url: http://git.joshuawise.com/netwatch.git/blobdiff_plain/112c8c75deab100cf02c2e9e850c9e8474ef1a92..421ccff4aaad4ddaba92ae0dba69fe6dbc9c1105:/net/rfb.c?ds=inline diff --git a/net/rfb.c b/net/rfb.c index 65323d1..1f620f0 100644 --- a/net/rfb.c +++ b/net/rfb.c @@ -14,7 +14,7 @@ #define POINTER_EVENT 5 #define CLIENT_CUT_TEXT 6 -#define RFB_BUF_SIZE 2048 +#define RFB_BUF_SIZE 64 struct pixel_format { uint8_t bpp; @@ -75,6 +75,17 @@ struct text_event_pkt { char text[]; }; +struct update_header { + uint8_t msgtype; + uint8_t padding; + uint16_t nrects; + uint16_t xpos; + uint16_t ypos; + uint16_t width; + uint16_t height; + int32_t enctype; +}; + struct rfb_state { enum { ST_BEGIN, @@ -89,31 +100,41 @@ struct rfb_state { int writepos; char next_update_incremental; + char update_requested; + struct fb_update_req client_interest_area; - int needs_updated; + enum { + SST_IDLE, + SST_NEEDS_UPDATE, + SST_SENDING + } send_state; + + uint32_t update_pos; + uint32_t frame_bytes; }; static struct server_init_message server_info; static void init_server_info() { - server_info.name_length = 8; + server_info.name_length = htonl(8); memcpy(server_info.name_string, "NetWatch", 8); } static void update_server_info() { if (fb != NULL) { - server_info.fb_width = fb->curmode.xres; - server_info.fb_height = fb->curmode.yres; + outputf("RFB: setting fmt %d", fb->curmode.format); + server_info.fb_width = htons(fb->curmode.xres); + server_info.fb_height = htons(fb->curmode.yres); switch (fb->curmode.format) { case FB_RGB888: server_info.fmt.bpp = 32; server_info.fmt.depth = 24; server_info.fmt.big_endian = 0; server_info.fmt.true_color = 1; - server_info.fmt.red_max = 255; - server_info.fmt.green_max = 255; - server_info.fmt.blue_max = 255; + server_info.fmt.red_max = htons(255); + server_info.fmt.green_max = htons(255); + server_info.fmt.blue_max = htons(255); server_info.fmt.red_shift = 0; server_info.fmt.green_shift = 8; server_info.fmt.blue_shift = 16; @@ -122,9 +143,92 @@ static void update_server_info() { outputf("RFB: unknown fb fmt %d", fb->curmode.format); break; } + } else { + outputf("RFB: fb null"); } } +static void send_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { + struct update_header hdr; + int left, sndlength; + err_t err; + + switch (state->send_state) { + case SST_IDLE: + /* Nothing to do */ + if (state->update_requested) { + outputf("RFB send: update requested"); + state->update_requested = 0; + state->send_state = SST_NEEDS_UPDATE; + } else { + break; + } + + /* FALL THROUGH to SST_NEEDS_UPDATE*/ + case SST_NEEDS_UPDATE: + outputf("RFB send: sending header"); + /* Send a header */ + state->frame_bytes = fb->curmode.xres * fb->curmode.yres * fb->curmode.bytestride; + hdr.msgtype = 0; + hdr.nrects = htons(1); + hdr.xpos = htons(0); + hdr.ypos = htons(0); + hdr.width = htons(fb->curmode.xres); + hdr.height = htons(fb->curmode.yres); + hdr.enctype = htonl(0); + tcp_write(pcb, &hdr, sizeof(hdr), TCP_WRITE_FLAG_COPY); + + state->update_pos = 0; + state->send_state = SST_SENDING; + + /* FALL THROUGH to SST_SENDING*/ + case SST_SENDING: + while (1) { + left = state->frame_bytes - state->update_pos; + + if (left == 0) { + state->send_state = SST_IDLE; + break; + } + + if (left > 8192) /* Sounds good enough to me. */ + left = 8192; + + sndlength = left; + do { + err = tcp_write(pcb, fb->fbaddr + state->update_pos, sndlength, TCP_WRITE_FLAG_COPY /* The card can't DMA from there. */); + if (err == ERR_MEM) /* Back down until lwip says we've got space. */ + sndlength /= 2; + } while (err == ERR_MEM && sndlength > 1); + + if (err != ERR_OK) { + if (err != ERR_MEM) + outputf("RFB: send error %d", err); + + /* We'll just give up for now and come back when we have space later. */ + break; + } + + state->update_pos += sndlength; + + if (tcp_sndbuf(pcb) == 0) { + break; + } + } + + break; + } + + if (tcp_output(pcb) != ERR_OK) + outputf("RFB: tcp_output bailed in send_fsm?"); +} + +static err_t rfb_sent(void *arg, struct tcp_pcb *pcb, uint16_t len) { + struct rfb_state *state = arg; + send_fsm(pcb, state); + return ERR_OK; +} + static void close_conn(struct tcp_pcb *pcb, struct rfb_state *state) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); @@ -140,6 +244,11 @@ enum fsm_result { }; static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { + int i; + int pktsize; + + outputf("RFB FSM: st %d rp %d wp %d", state->state, state->readpos, + state->writepos); switch(state->state) { case ST_BEGIN: @@ -165,25 +274,33 @@ static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { state->readpos += 12; state->state = ST_CLIENTINIT; - /* We support one security type, currently "none". */ + /* We support one security type, currently "none". + * Send that and SecurityResult. */ if (state->version >= 7) { - tcp_write(pcb, "\x01\x01", 2, 0); + tcp_write(pcb, "\x01\x01\x00\x00\x00\x00", 6, 0); } else { - tcp_write(pcb, "\x01", 1, 0); + tcp_write(pcb, "\x01\x00\x00\x00\x00", 5, 0); } - /* ... and go right ahead and send SecurityResult message. */ - tcp_write(pcb, "\x00\x00\x00\x01", 4, 0); tcp_output(pcb); return OK; case ST_CLIENTINIT: - if (state->writepos < 1) return NEEDMORE; - state->readpos += 1; + if (state->version >= 7) { + /* Ignore the security type and ClientInit */ + if (state->writepos < 2) return NEEDMORE; + state->readpos += 2; + } else { + /* Just ClientInit */ + if (state->writepos < 1) return NEEDMORE; + state->readpos += 1; + } + state->state = ST_MAIN; - tcp_write(pcb, &server_info, sizeof(server_info), 0); + outputf("RFB: Sending server info", state->version); + tcp_write(pcb, &server_info, sizeof(server_info), TCP_WRITE_FLAG_COPY); tcp_output(pcb); return OK; @@ -191,12 +308,14 @@ static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { case ST_MAIN: if (state->writepos < 1) return NEEDMORE; + outputf("RFB: cmd %d", state->data[0]); switch (state->data[0]) { case SET_PIXEL_FORMAT: /* SetPixelFormat */ if (state->writepos < (sizeof(struct pixel_format) + 4)) return NEEDMORE; + outputf("RFB: SetPixelFormat"); /* struct pixel_format * new_fmt = (struct pixel_format *)(&state->data[4]); @@ -211,20 +330,25 @@ static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { struct set_encs_req * req = (struct set_encs_req *)state->data; - if (state->writepos < (sizeof(struct set_encs_req) - + 4 * req->num)) - return NEEDMORE; + pktsize = sizeof(struct set_encs_req) + (4 * ntohs(req->num)); - /* XXX ... */ + outputf("RFB: SetEncodings [%d]", ntohs(req->num)); + if (state->writepos < pktsize) return NEEDMORE; + + for (i = 0; i < ntohs(req->num); i++) { + outputf("RFB: Encoding: %d", ntohl(req->encodings[i])); + /* XXX ... */ + } - state->readpos += (4 * req->num) + sizeof(struct set_encs_req); + state->readpos += pktsize; return OK; case FB_UPDATE_REQUEST: if (state->writepos < sizeof(struct fb_update_req)) return NEEDMORE; + outputf("RFB: UpdateRequest"); - state->needs_updated = 1; + state->update_requested = 1; memcpy(&state->client_interest_area, state->data, sizeof(struct fb_update_req)); @@ -234,6 +358,7 @@ static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { case KEY_EVENT: if (state->writepos < sizeof(struct key_event_pkt)) return NEEDMORE; + outputf("RFB: Key"); /* XXX stub */ @@ -243,6 +368,7 @@ static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { case POINTER_EVENT: if (state->writepos < sizeof(struct pointer_event_pkt)) return NEEDMORE; + outputf("RFB: Pointer"); /* XXX stub */ @@ -252,6 +378,7 @@ static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { case CLIENT_CUT_TEXT: if (state->writepos < sizeof(struct text_event_pkt)) return NEEDMORE; + outputf("RFB: Cut Text"); struct text_event_pkt * pkt = (struct text_event_pkt *)state->data; @@ -302,16 +429,27 @@ static err_t rfb_recv(void *arg, struct tcp_pcb *pcb, outputf("RFB: Processing %d", p->tot_len); pbuf_copy_partial(p, state->data + state->writepos, p->tot_len, 0); + state->writepos += p->tot_len; + tcp_recved(pcb, p->tot_len); pbuf_free(p); while (1) { switch (recv_fsm(pcb, state)) { case NEEDMORE: + outputf("RFB FSM: blocking"); /* Need more data */ return ERR_OK; case OK: + outputf("RFB FSM: ok"); + + /* Kick off a send. */ + if (state->send_state == SST_IDLE + && state->update_requested) { + send_fsm(pcb, state); + } + if (state->readpos == state->writepos) { state->readpos = 0; state->writepos = 0; @@ -339,6 +477,12 @@ static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) { state = (struct rfb_state *)mem_malloc(sizeof(struct rfb_state)); + state->state = ST_BEGIN; + state->readpos = 0; + state->writepos = 0; + state->update_requested = 0; + state->send_state = SST_IDLE; + /* XXX: update_server_info() should be called from the 64ms timer, and deal * with screen resizes appropriately. */ update_server_info(); @@ -351,6 +495,7 @@ static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) { tcp_arg(pcb, state); tcp_recv(pcb, rfb_recv); + tcp_sent(pcb, rfb_sent); /* tcp_err(pcb, rfb_err); tcp_poll(pcb, rfb_poll, 2);