From: Jacob Potter Date: Tue, 25 Nov 2008 10:00:36 +0000 (-0500) Subject: initial checkin of RFB X-Git-Url: http://git.joshuawise.com/netwatch.git/commitdiff_plain/7da36fbdd33af46634d7ac7a6ebae1ea213f64dd?ds=inline;hp=--cc initial checkin of RFB --- 7da36fbdd33af46634d7ac7a6ebae1ea213f64dd diff --git a/aseg-paging/Makefile b/aseg-paging/Makefile index c9a8f43..ec70ea4 100644 --- a/aseg-paging/Makefile +++ b/aseg-paging/Makefile @@ -43,6 +43,7 @@ OBJS = ../ich2/smi.o \ ../net/http/fs.o \ ../net/http/httpd.o \ ../net/3c90x.o \ + ../net/rfb.o \ ../video/tnt2.o \ ../video/fb.o \ drivers.o \ diff --git a/net/net.c b/net/net.c index 52ab38f..5b4072b 100644 --- a/net/net.c +++ b/net/net.c @@ -18,6 +18,8 @@ #include "netif/etharp.h" #include "netif/ppp_oe.h" +#include "rfb.h" + static struct nic *_nic = 0x0; static struct netif _netif; @@ -160,4 +162,7 @@ void eth_init() smram_tseg_set_state(SMRAM_TSEG_OPEN); lwip_init(); httpd_init(); +/* + rfb_init(); +*/ } diff --git a/net/rfb.c b/net/rfb.c new file mode 100644 index 0000000..65323d1 --- /dev/null +++ b/net/rfb.c @@ -0,0 +1,373 @@ +#include +#include +#include +#include + +#include "lwip/tcp.h" + +#include "rfb.h" + +#define SET_PIXEL_FORMAT 0 +#define SET_ENCODINGS 2 +#define FB_UPDATE_REQUEST 3 +#define KEY_EVENT 4 +#define POINTER_EVENT 5 +#define CLIENT_CUT_TEXT 6 + +#define RFB_BUF_SIZE 2048 + +struct pixel_format { + uint8_t bpp; + uint8_t depth; + uint8_t big_endian; + uint8_t true_color; + uint16_t red_max; + uint16_t green_max; + uint16_t blue_max; + uint8_t red_shift; + uint8_t green_shift; + uint8_t blue_shift; + uint8_t padding[3]; +}; + +struct server_init_message { + uint16_t fb_width; + uint16_t fb_height; + struct pixel_format fmt; + uint32_t name_length; + char name_string[8]; +}; + +struct fb_update_req { + uint8_t msgtype; + uint8_t incremental; + uint16_t xpos; + uint16_t ypos; + uint16_t width; + uint16_t height; +}; + +struct set_encs_req { + uint8_t msgtype; + uint8_t padding; + uint16_t num; + int32_t encodings[]; +}; + +struct key_event_pkt { + uint8_t msgtype; + uint8_t downflag; + uint8_t pad[2]; + uint32_t keysym; +}; + +struct pointer_event_pkt { + uint8_t msgtype; + uint8_t button_mask; + uint16_t x; + uint16_t y; +}; + +struct text_event_pkt { + uint8_t msgtype; + uint8_t padding[3]; + uint32_t length; + char text[]; +}; + +struct rfb_state { + enum { + ST_BEGIN, + ST_CLIENTINIT, + ST_MAIN + } state; + int version; + int encs_remaining; + + char data[RFB_BUF_SIZE]; + int readpos; + int writepos; + + char next_update_incremental; + struct fb_update_req client_interest_area; + + int needs_updated; +}; + +static struct server_init_message server_info; + +static void init_server_info() { + server_info.name_length = 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; + 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_shift = 0; + server_info.fmt.green_shift = 8; + server_info.fmt.blue_shift = 16; + break; + default: + outputf("RFB: unknown fb fmt %d", fb->curmode.format); + break; + } + } +} + +static void close_conn(struct tcp_pcb *pcb, struct rfb_state *state) { + tcp_arg(pcb, NULL); + tcp_sent(pcb, NULL); + tcp_recv(pcb, NULL); + mem_free(state); + tcp_close(pcb); +} + +enum fsm_result { + NEEDMORE, + OK, + FAIL +}; + +static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) { + + switch(state->state) { + case ST_BEGIN: + if (state->writepos < 12) return NEEDMORE; + + if (!strncmp(state->data, "RFB 003.003\n", 12)) { + state->version = 3; + } else if (!strncmp(state->data, "RFB 003.005\n", 12)) { + /* Spec states that "RFB 003.005", an incorrect value, + * should be treated by the server as 3.3. */ + state->version = 3; + } else if (!strncmp(state->data, "RFB 003.007\n", 12)) { + state->version = 7; + } else if (!strncmp(state->data, "RFB 003.008\n", 12)) { + state->version = 8; + } else { + outputf("RFB: Negotiation fail"); + return FAIL; + } + + outputf("RFB: Negotiated v3.%d", state->version); + + state->readpos += 12; + state->state = ST_CLIENTINIT; + + /* We support one security type, currently "none". */ + if (state->version >= 7) { + tcp_write(pcb, "\x01\x01", 2, 0); + } else { + tcp_write(pcb, "\x01", 1, 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; + state->state = ST_MAIN; + + tcp_write(pcb, &server_info, sizeof(server_info), 0); + tcp_output(pcb); + + return OK; + + case ST_MAIN: + if (state->writepos < 1) return NEEDMORE; + + switch (state->data[0]) { + + case SET_PIXEL_FORMAT: + /* SetPixelFormat */ + if (state->writepos < (sizeof(struct pixel_format) + 4)) + return NEEDMORE; +/* + struct pixel_format * new_fmt = + (struct pixel_format *)(&state->data[4]); +*/ + /* XXX ... */ + + state->readpos += sizeof(struct pixel_format) + 4; + return OK; + + case SET_ENCODINGS: + if (state->writepos < 4) return NEEDMORE; + + struct set_encs_req * req = (struct set_encs_req *)state->data; + + if (state->writepos < (sizeof(struct set_encs_req) + + 4 * req->num)) + return NEEDMORE; + + /* XXX ... */ + + state->readpos += (4 * req->num) + sizeof(struct set_encs_req); + return OK; + + case FB_UPDATE_REQUEST: + if (state->writepos < sizeof(struct fb_update_req)) + return NEEDMORE; + + state->needs_updated = 1; + memcpy(&state->client_interest_area, state->data, + sizeof(struct fb_update_req)); + + state->readpos += sizeof(struct fb_update_req); + return OK; + + case KEY_EVENT: + if (state->writepos < sizeof(struct key_event_pkt)) + return NEEDMORE; + + /* XXX stub */ + + state->readpos += sizeof(struct key_event_pkt); + return OK; + + case POINTER_EVENT: + if (state->writepos < sizeof(struct pointer_event_pkt)) + return NEEDMORE; + + /* XXX stub */ + + state->readpos += sizeof(struct pointer_event_pkt); + return OK; + + case CLIENT_CUT_TEXT: + if (state->writepos < sizeof(struct text_event_pkt)) + return NEEDMORE; + + struct text_event_pkt * pkt = + (struct text_event_pkt *)state->data; + + if (state->writepos < sizeof(struct text_event_pkt) + + pkt->length) + return NEEDMORE; + + /* XXX stub */ + + state->readpos += sizeof(struct text_event_pkt) + + pkt->length; + return OK; + + default: + outputf("RFB: Bad command: %d", state->data[0]); + } + default: + outputf("RFB: Bad state"); + return FAIL; + } +} + +static err_t rfb_recv(void *arg, struct tcp_pcb *pcb, + struct pbuf *p, err_t err) { + struct rfb_state *state = arg; + + if (state == NULL) + + if (err != ERR_OK) { + outputf("RFB: recv err %d", err); + /* FIXME do something better here? */ + return ERR_OK; + } + + if (p == NULL) { + outputf("RFB: Connection closed"); + close_conn(pcb, state); + return ERR_OK; + } + + if (p->tot_len > (RFB_BUF_SIZE - state->writepos)) { + /* Overflow! */ + outputf("RFB: Overflow!"); + close_conn(pcb, state); + return ERR_OK; + } + + outputf("RFB: Processing %d", p->tot_len); + pbuf_copy_partial(p, state->data + state->writepos, p->tot_len, 0); + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + + while (1) { + switch (recv_fsm(pcb, state)) { + case NEEDMORE: + /* Need more data */ + return ERR_OK; + + case OK: + if (state->readpos == state->writepos) { + state->readpos = 0; + state->writepos = 0; + return ERR_OK; + } else { + memmove(state->data, + state->data + state->readpos, + state->writepos - state->readpos); + } + break; + case FAIL: + /* Shit */ + outputf("RFB: Protocol error"); + close_conn(pcb, state); + return ERR_OK; + } + } +} + +static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) { + struct rfb_state *state; + + LWIP_UNUSED_ARG(arg); + LWIP_UNUSED_ARG(err); + + state = (struct rfb_state *)mem_malloc(sizeof(struct rfb_state)); + + /* XXX: update_server_info() should be called from the 64ms timer, and deal + * with screen resizes appropriately. */ + update_server_info(); + + if (!state) + { + outputf("rfb_accept: out of memory\n"); + return ERR_MEM; + } + + tcp_arg(pcb, state); + tcp_recv(pcb, rfb_recv); +/* + tcp_err(pcb, rfb_err); + tcp_poll(pcb, rfb_poll, 2); +*/ + tcp_write(pcb, "RFB 003.008\n", 12, 0); + tcp_output(pcb); + + return ERR_OK; +} + +void rfb_init() { + struct tcp_pcb *pcb; + + init_server_info(); + + pcb = tcp_new(); + tcp_bind(pcb, IP_ADDR_ANY, RFB_PORT); + pcb = tcp_listen(pcb); + tcp_accept(pcb, rfb_accept); +} diff --git a/net/rfb.h b/net/rfb.h new file mode 100644 index 0000000..601e2f5 --- /dev/null +++ b/net/rfb.h @@ -0,0 +1,8 @@ +#ifndef _RFB_H +#define _RFB_H + +void rfb_init(void); + +#define RFB_PORT 5900 + +#endif /* _RFB_H */