]> Joshua Wise's Git repositories - netwatch.git/commitdiff
initial checkin of RFB
authorJacob Potter <jdpotter@andrew.cmu.edu>
Tue, 25 Nov 2008 10:00:36 +0000 (05:00 -0500)
committerJacob Potter <jdpotter@andrew.cmu.edu>
Tue, 25 Nov 2008 10:00:36 +0000 (05:00 -0500)
aseg-paging/Makefile
net/net.c
net/rfb.c [new file with mode: 0644]
net/rfb.h [new file with mode: 0644]

index c9a8f439b008e3eaa9da0c20b543d6c6cf4b89dd..ec70ea4b9aed4bac2323809f93d03ec31152904a 100644 (file)
@@ -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 \
index 52ab38f155db69cbd7b2b1bcace5bd295df2ff7d..5b4072b111c278b8b009c1cb79dda6e7397944de 100644 (file)
--- 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 (file)
index 0000000..65323d1
--- /dev/null
+++ b/net/rfb.c
@@ -0,0 +1,373 @@
+#include <stdint.h>
+#include <minilib.h>
+#include <output.h>
+#include <fb.h>
+
+#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 (file)
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 */
This page took 0.042709 seconds and 4 git commands to generate.