]> Joshua Wise's Git repositories - netwatch.git/blame - net/rfb.c
Merge branch 'master' of /storage/git/netwatch
[netwatch.git] / net / rfb.c
CommitLineData
7da36fbd
JP
1#include <stdint.h>
2#include <minilib.h>
3#include <output.h>
4#include <fb.h>
5
6#include "lwip/tcp.h"
7
8#include "rfb.h"
9
10#define SET_PIXEL_FORMAT 0
11#define SET_ENCODINGS 2
12#define FB_UPDATE_REQUEST 3
13#define KEY_EVENT 4
14#define POINTER_EVENT 5
15#define CLIENT_CUT_TEXT 6
16
17#define RFB_BUF_SIZE 2048
18
19struct pixel_format {
20 uint8_t bpp;
21 uint8_t depth;
22 uint8_t big_endian;
23 uint8_t true_color;
24 uint16_t red_max;
25 uint16_t green_max;
26 uint16_t blue_max;
27 uint8_t red_shift;
28 uint8_t green_shift;
29 uint8_t blue_shift;
30 uint8_t padding[3];
31};
32
33struct server_init_message {
34 uint16_t fb_width;
35 uint16_t fb_height;
36 struct pixel_format fmt;
37 uint32_t name_length;
38 char name_string[8];
39};
40
41struct fb_update_req {
42 uint8_t msgtype;
43 uint8_t incremental;
44 uint16_t xpos;
45 uint16_t ypos;
46 uint16_t width;
47 uint16_t height;
48};
49
50struct set_encs_req {
51 uint8_t msgtype;
52 uint8_t padding;
53 uint16_t num;
54 int32_t encodings[];
55};
56
57struct key_event_pkt {
58 uint8_t msgtype;
59 uint8_t downflag;
60 uint8_t pad[2];
61 uint32_t keysym;
62};
63
64struct pointer_event_pkt {
65 uint8_t msgtype;
66 uint8_t button_mask;
67 uint16_t x;
68 uint16_t y;
69};
70
71struct text_event_pkt {
72 uint8_t msgtype;
73 uint8_t padding[3];
74 uint32_t length;
75 char text[];
76};
77
78struct rfb_state {
79 enum {
80 ST_BEGIN,
81 ST_CLIENTINIT,
82 ST_MAIN
83 } state;
84 int version;
85 int encs_remaining;
86
87 char data[RFB_BUF_SIZE];
88 int readpos;
89 int writepos;
90
91 char next_update_incremental;
92 struct fb_update_req client_interest_area;
93
94 int needs_updated;
95};
96
97static struct server_init_message server_info;
98
99static void init_server_info() {
100 server_info.name_length = 8;
101 memcpy(server_info.name_string, "NetWatch", 8);
102}
103
104static void update_server_info() {
105 if (fb != NULL) {
106 server_info.fb_width = fb->curmode.xres;
107 server_info.fb_height = fb->curmode.yres;
108 switch (fb->curmode.format) {
109 case FB_RGB888:
110 server_info.fmt.bpp = 32;
111 server_info.fmt.depth = 24;
112 server_info.fmt.big_endian = 0;
113 server_info.fmt.true_color = 1;
114 server_info.fmt.red_max = 255;
115 server_info.fmt.green_max = 255;
116 server_info.fmt.blue_max = 255;
117 server_info.fmt.red_shift = 0;
118 server_info.fmt.green_shift = 8;
119 server_info.fmt.blue_shift = 16;
120 break;
121 default:
122 outputf("RFB: unknown fb fmt %d", fb->curmode.format);
123 break;
124 }
125 }
126}
127
128static void close_conn(struct tcp_pcb *pcb, struct rfb_state *state) {
129 tcp_arg(pcb, NULL);
130 tcp_sent(pcb, NULL);
131 tcp_recv(pcb, NULL);
132 mem_free(state);
133 tcp_close(pcb);
134}
135
136enum fsm_result {
137 NEEDMORE,
138 OK,
139 FAIL
140};
141
142static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) {
143
144 switch(state->state) {
145 case ST_BEGIN:
146 if (state->writepos < 12) return NEEDMORE;
147
148 if (!strncmp(state->data, "RFB 003.003\n", 12)) {
149 state->version = 3;
150 } else if (!strncmp(state->data, "RFB 003.005\n", 12)) {
151 /* Spec states that "RFB 003.005", an incorrect value,
152 * should be treated by the server as 3.3. */
153 state->version = 3;
154 } else if (!strncmp(state->data, "RFB 003.007\n", 12)) {
155 state->version = 7;
156 } else if (!strncmp(state->data, "RFB 003.008\n", 12)) {
157 state->version = 8;
158 } else {
159 outputf("RFB: Negotiation fail");
160 return FAIL;
161 }
162
163 outputf("RFB: Negotiated v3.%d", state->version);
164
165 state->readpos += 12;
166 state->state = ST_CLIENTINIT;
167
168 /* We support one security type, currently "none". */
169 if (state->version >= 7) {
170 tcp_write(pcb, "\x01\x01", 2, 0);
171 } else {
172 tcp_write(pcb, "\x01", 1, 0);
173 }
174
175 /* ... and go right ahead and send SecurityResult message. */
176 tcp_write(pcb, "\x00\x00\x00\x01", 4, 0);
177 tcp_output(pcb);
178
179 return OK;
180
181 case ST_CLIENTINIT:
182 if (state->writepos < 1) return NEEDMORE;
183 state->readpos += 1;
184 state->state = ST_MAIN;
185
186 tcp_write(pcb, &server_info, sizeof(server_info), 0);
187 tcp_output(pcb);
188
189 return OK;
190
191 case ST_MAIN:
192 if (state->writepos < 1) return NEEDMORE;
193
194 switch (state->data[0]) {
195
196 case SET_PIXEL_FORMAT:
197 /* SetPixelFormat */
198 if (state->writepos < (sizeof(struct pixel_format) + 4))
199 return NEEDMORE;
200/*
201 struct pixel_format * new_fmt =
202 (struct pixel_format *)(&state->data[4]);
203*/
204 /* XXX ... */
205
206 state->readpos += sizeof(struct pixel_format) + 4;
207 return OK;
208
209 case SET_ENCODINGS:
210 if (state->writepos < 4) return NEEDMORE;
211
212 struct set_encs_req * req = (struct set_encs_req *)state->data;
213
214 if (state->writepos < (sizeof(struct set_encs_req)
215 + 4 * req->num))
216 return NEEDMORE;
217
218 /* XXX ... */
219
220 state->readpos += (4 * req->num) + sizeof(struct set_encs_req);
221 return OK;
222
223 case FB_UPDATE_REQUEST:
224 if (state->writepos < sizeof(struct fb_update_req))
225 return NEEDMORE;
226
227 state->needs_updated = 1;
228 memcpy(&state->client_interest_area, state->data,
229 sizeof(struct fb_update_req));
230
231 state->readpos += sizeof(struct fb_update_req);
232 return OK;
233
234 case KEY_EVENT:
235 if (state->writepos < sizeof(struct key_event_pkt))
236 return NEEDMORE;
237
238 /* XXX stub */
239
240 state->readpos += sizeof(struct key_event_pkt);
241 return OK;
242
243 case POINTER_EVENT:
244 if (state->writepos < sizeof(struct pointer_event_pkt))
245 return NEEDMORE;
246
247 /* XXX stub */
248
249 state->readpos += sizeof(struct pointer_event_pkt);
250 return OK;
251
252 case CLIENT_CUT_TEXT:
253 if (state->writepos < sizeof(struct text_event_pkt))
254 return NEEDMORE;
255
256 struct text_event_pkt * pkt =
257 (struct text_event_pkt *)state->data;
258
259 if (state->writepos < sizeof(struct text_event_pkt)
260 + pkt->length)
261 return NEEDMORE;
262
263 /* XXX stub */
264
265 state->readpos += sizeof(struct text_event_pkt)
266 + pkt->length;
267 return OK;
268
269 default:
270 outputf("RFB: Bad command: %d", state->data[0]);
271 }
272 default:
273 outputf("RFB: Bad state");
274 return FAIL;
275 }
276}
277
278static err_t rfb_recv(void *arg, struct tcp_pcb *pcb,
279 struct pbuf *p, err_t err) {
280 struct rfb_state *state = arg;
281
282 if (state == NULL)
283
284 if (err != ERR_OK) {
285 outputf("RFB: recv err %d", err);
286 /* FIXME do something better here? */
287 return ERR_OK;
288 }
289
290 if (p == NULL) {
291 outputf("RFB: Connection closed");
292 close_conn(pcb, state);
293 return ERR_OK;
294 }
295
296 if (p->tot_len > (RFB_BUF_SIZE - state->writepos)) {
297 /* Overflow! */
298 outputf("RFB: Overflow!");
299 close_conn(pcb, state);
300 return ERR_OK;
301 }
302
303 outputf("RFB: Processing %d", p->tot_len);
304 pbuf_copy_partial(p, state->data + state->writepos, p->tot_len, 0);
305 tcp_recved(pcb, p->tot_len);
306 pbuf_free(p);
307
308 while (1) {
309 switch (recv_fsm(pcb, state)) {
310 case NEEDMORE:
311 /* Need more data */
312 return ERR_OK;
313
314 case OK:
315 if (state->readpos == state->writepos) {
316 state->readpos = 0;
317 state->writepos = 0;
318 return ERR_OK;
319 } else {
320 memmove(state->data,
321 state->data + state->readpos,
322 state->writepos - state->readpos);
323 }
324 break;
325 case FAIL:
326 /* Shit */
327 outputf("RFB: Protocol error");
328 close_conn(pcb, state);
329 return ERR_OK;
330 }
331 }
332}
333
334static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
335 struct rfb_state *state;
336
337 LWIP_UNUSED_ARG(arg);
338 LWIP_UNUSED_ARG(err);
339
340 state = (struct rfb_state *)mem_malloc(sizeof(struct rfb_state));
341
342 /* XXX: update_server_info() should be called from the 64ms timer, and deal
343 * with screen resizes appropriately. */
344 update_server_info();
345
346 if (!state)
347 {
348 outputf("rfb_accept: out of memory\n");
349 return ERR_MEM;
350 }
351
352 tcp_arg(pcb, state);
353 tcp_recv(pcb, rfb_recv);
354/*
355 tcp_err(pcb, rfb_err);
356 tcp_poll(pcb, rfb_poll, 2);
357*/
358 tcp_write(pcb, "RFB 003.008\n", 12, 0);
359 tcp_output(pcb);
360
361 return ERR_OK;
362}
363
364void rfb_init() {
365 struct tcp_pcb *pcb;
366
367 init_server_info();
368
369 pcb = tcp_new();
370 tcp_bind(pcb, IP_ADDR_ANY, RFB_PORT);
371 pcb = tcp_listen(pcb);
372 tcp_accept(pcb, rfb_accept);
373}
This page took 0.05227 seconds and 4 git commands to generate.