10 #define SET_PIXEL_FORMAT 0
11 #define SET_ENCODINGS 2
12 #define FB_UPDATE_REQUEST 3
14 #define POINTER_EVENT 5
15 #define CLIENT_CUT_TEXT 6
17 #define RFB_BUF_SIZE 64
33 struct server_init_message {
36 struct pixel_format fmt;
41 struct fb_update_req {
57 struct key_event_pkt {
64 struct pointer_event_pkt {
71 struct text_event_pkt {
87 char data[RFB_BUF_SIZE];
91 char next_update_incremental;
92 struct fb_update_req client_interest_area;
94 uint8_t update_allowed;
98 static struct server_init_message server_info;
100 static void init_server_info() {
101 server_info.name_length = htonl(8);
102 memcpy(server_info.name_string, "NetWatch", 8);
105 static void update_server_info() {
107 outputf("RFB: setting fmt %d", fb->curmode.format);
108 server_info.fb_width = htons(fb->curmode.xres);
109 server_info.fb_height = htons(fb->curmode.yres);
110 switch (fb->curmode.format) {
112 server_info.fmt.bpp = 32;
113 server_info.fmt.depth = 24;
114 server_info.fmt.big_endian = 0;
115 server_info.fmt.true_color = 1;
116 server_info.fmt.red_max = htons(255);
117 server_info.fmt.green_max = htons(255);
118 server_info.fmt.blue_max = htons(255);
119 server_info.fmt.red_shift = 0;
120 server_info.fmt.green_shift = 8;
121 server_info.fmt.blue_shift = 16;
124 outputf("RFB: unknown fb fmt %d", fb->curmode.format);
128 outputf("RFB: fb null");
132 static void start_send(struct tcp_pcb *pcb, struct rfb_state *state) {
136 static void close_conn(struct tcp_pcb *pcb, struct rfb_state *state) {
150 static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) {
154 outputf("RFB FSM: st %d rp %d wp %d", state->state, state->readpos,
157 switch(state->state) {
159 if (state->writepos < 12) return NEEDMORE;
161 if (!strncmp(state->data, "RFB 003.003\n", 12)) {
163 } else if (!strncmp(state->data, "RFB 003.005\n", 12)) {
164 /* Spec states that "RFB 003.005", an incorrect value,
165 * should be treated by the server as 3.3. */
167 } else if (!strncmp(state->data, "RFB 003.007\n", 12)) {
169 } else if (!strncmp(state->data, "RFB 003.008\n", 12)) {
172 outputf("RFB: Negotiation fail");
176 outputf("RFB: Negotiated v3.%d", state->version);
178 state->readpos += 12;
179 state->state = ST_CLIENTINIT;
181 /* We support one security type, currently "none".
182 * Send that and SecurityResult. */
183 if (state->version >= 7) {
184 tcp_write(pcb, "\x01\x01\x00\x00\x00\x00", 6, 0);
186 tcp_write(pcb, "\x01\x00\x00\x00\x00", 5, 0);
194 if (state->version >= 7) {
195 /* Ignore the security type and ClientInit */
196 if (state->writepos < 2) return NEEDMORE;
199 /* Just ClientInit */
200 if (state->writepos < 1) return NEEDMORE;
204 state->state = ST_MAIN;
206 outputf("RFB: Sending server info", state->version);
207 tcp_write(pcb, &server_info, sizeof(server_info), 0);
213 if (state->writepos < 1) return NEEDMORE;
215 outputf("RFB: cmd %d", state->data[0]);
216 switch (state->data[0]) {
218 case SET_PIXEL_FORMAT:
220 if (state->writepos < (sizeof(struct pixel_format) + 4))
222 outputf("RFB: SetPixelFormat");
224 struct pixel_format * new_fmt =
225 (struct pixel_format *)(&state->data[4]);
229 state->readpos += sizeof(struct pixel_format) + 4;
233 if (state->writepos < 4) return NEEDMORE;
235 struct set_encs_req * req = (struct set_encs_req *)state->data;
237 pktsize = sizeof(struct set_encs_req) + (4 * ntohs(req->num));
239 outputf("RFB: SetEncodings [%d]", ntohs(req->num));
240 if (state->writepos < pktsize) return NEEDMORE;
242 for (i = 0; i < ntohs(req->num); i++) {
243 outputf("RFB: Encoding: %d", ntohl(req->encodings[i]));
248 state->readpos += pktsize;
251 case FB_UPDATE_REQUEST:
252 if (state->writepos < sizeof(struct fb_update_req))
254 outputf("RFB: UpdateRequest");
256 state->update_allowed = 1;
257 memcpy(&state->client_interest_area, state->data,
258 sizeof(struct fb_update_req));
260 state->readpos += sizeof(struct fb_update_req);
264 if (state->writepos < sizeof(struct key_event_pkt))
270 state->readpos += sizeof(struct key_event_pkt);
274 if (state->writepos < sizeof(struct pointer_event_pkt))
276 outputf("RFB: Pointer");
280 state->readpos += sizeof(struct pointer_event_pkt);
283 case CLIENT_CUT_TEXT:
284 if (state->writepos < sizeof(struct text_event_pkt))
286 outputf("RFB: Cut Text");
288 struct text_event_pkt * pkt =
289 (struct text_event_pkt *)state->data;
291 if (state->writepos < sizeof(struct text_event_pkt)
297 state->readpos += sizeof(struct text_event_pkt)
302 outputf("RFB: Bad command: %d", state->data[0]);
305 outputf("RFB: Bad state");
310 static err_t rfb_recv(void *arg, struct tcp_pcb *pcb,
311 struct pbuf *p, err_t err) {
312 struct rfb_state *state = arg;
317 outputf("RFB: recv err %d", err);
318 /* FIXME do something better here? */
323 outputf("RFB: Connection closed");
324 close_conn(pcb, state);
328 if (p->tot_len > (RFB_BUF_SIZE - state->writepos)) {
330 outputf("RFB: Overflow!");
331 close_conn(pcb, state);
335 outputf("RFB: Processing %d", p->tot_len);
336 pbuf_copy_partial(p, state->data + state->writepos, p->tot_len, 0);
337 state->writepos += p->tot_len;
339 tcp_recved(pcb, p->tot_len);
343 switch (recv_fsm(pcb, state)) {
345 outputf("RFB FSM: blocking");
350 outputf("RFB FSM: ok");
352 /* Might as well send now... */
353 if (state->update_allowed && !state->sending) {
354 start_send(pcb, state);
357 if (state->readpos == state->writepos) {
363 state->data + state->readpos,
364 state->writepos - state->readpos);
369 outputf("RFB: Protocol error");
370 close_conn(pcb, state);
376 static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
377 struct rfb_state *state;
379 LWIP_UNUSED_ARG(arg);
380 LWIP_UNUSED_ARG(err);
382 state = (struct rfb_state *)mem_malloc(sizeof(struct rfb_state));
384 state->state = ST_BEGIN;
387 state->update_allowed = 0;
390 /* XXX: update_server_info() should be called from the 64ms timer, and deal
391 * with screen resizes appropriately. */
392 update_server_info();
396 outputf("rfb_accept: out of memory\n");
401 tcp_recv(pcb, rfb_recv);
403 tcp_err(pcb, rfb_err);
404 tcp_poll(pcb, rfb_poll, 2);
406 tcp_write(pcb, "RFB 003.008\n", 12, 0);
418 tcp_bind(pcb, IP_ADDR_ANY, RFB_PORT);
419 pcb = tcp_listen(pcb);
420 tcp_accept(pcb, rfb_accept);