]> Joshua Wise's Git repositories - netwatch.git/blob - net/rfb.c
We do not speak Pittsburgh here.
[netwatch.git] / net / rfb.c
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    64
18
19 struct 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
33 struct 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
41 struct 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
50 struct set_encs_req {
51         uint8_t msgtype;
52         uint8_t padding;
53         uint16_t num;
54         int32_t encodings[];
55 };
56
57 struct key_event_pkt {
58         uint8_t msgtype;
59         uint8_t downflag;
60         uint8_t pad[2];
61         uint32_t keysym;
62 };
63
64 struct pointer_event_pkt {
65         uint8_t msgtype;
66         uint8_t button_mask;
67         uint16_t x;
68         uint16_t y;
69 };
70
71 struct text_event_pkt {
72         uint8_t msgtype;
73         uint8_t padding[3];
74         uint32_t length;
75         char text[];
76 };
77
78 struct 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         uint8_t update_allowed;
95         uint8_t sending;
96 };
97
98 static struct server_init_message server_info;
99
100 static void init_server_info() {
101         server_info.name_length = htonl(8);
102         memcpy(server_info.name_string, "NetWatch", 8);
103 }
104
105 static void update_server_info() {
106         if (fb != NULL) {
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) {
111                 case FB_RGB888:
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;
122                         break;
123                 default:
124                         outputf("RFB: unknown fb fmt %d", fb->curmode.format);
125                         break;
126                 }
127         } else {
128                 outputf("RFB: fb null");
129         }
130 }
131
132 static void start_send(struct tcp_pcb *pcb, struct rfb_state *state) {
133         /* ... */
134 }
135
136 static void close_conn(struct tcp_pcb *pcb, struct rfb_state *state) {
137         tcp_arg(pcb, NULL);
138         tcp_sent(pcb, NULL);
139         tcp_recv(pcb, NULL);
140         mem_free(state);
141         tcp_close(pcb);
142 }
143
144 enum fsm_result {
145         NEEDMORE,
146         OK,
147         FAIL
148 };
149
150 static enum fsm_result recv_fsm(struct tcp_pcb *pcb, struct rfb_state *state) {
151         int i;
152         int pktsize;
153
154         outputf("RFB FSM: st %d rp %d wp %d", state->state, state->readpos,
155                 state->writepos);
156
157         switch(state->state) {
158         case ST_BEGIN:
159                 if (state->writepos < 12) return NEEDMORE;
160
161                 if (!strncmp(state->data, "RFB 003.003\n", 12)) {
162                         state->version = 3;
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. */
166                         state->version = 3;
167                 } else if (!strncmp(state->data, "RFB 003.007\n", 12)) {
168                         state->version = 7;
169                 } else if (!strncmp(state->data, "RFB 003.008\n", 12)) {
170                         state->version = 8;
171                 } else {
172                         outputf("RFB: Negotiation fail");
173                         return FAIL;
174                 }
175
176                 outputf("RFB: Negotiated v3.%d", state->version);
177
178                 state->readpos += 12;
179                 state->state = ST_CLIENTINIT;
180
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);
185                 } else {
186                         tcp_write(pcb, "\x01\x00\x00\x00\x00", 5, 0);
187                 }
188
189                 tcp_output(pcb);
190
191                 return OK;
192
193         case ST_CLIENTINIT:
194                 if (state->version >= 7) {
195                         /* Ignore the security type and ClientInit */
196                         if (state->writepos < 2) return NEEDMORE;
197                         state->readpos += 2;
198                 } else {
199                         /* Just ClientInit */
200                         if (state->writepos < 1) return NEEDMORE;
201                         state->readpos += 1;
202                 }
203
204                 state->state = ST_MAIN;
205
206                 outputf("RFB: Sending server info", state->version);
207                 tcp_write(pcb, &server_info, sizeof(server_info), 0);
208                 tcp_output(pcb);
209
210                 return OK;
211
212         case ST_MAIN:
213                 if (state->writepos < 1) return NEEDMORE;
214
215                 outputf("RFB: cmd %d", state->data[0]);
216                 switch (state->data[0]) {
217
218                 case SET_PIXEL_FORMAT:
219                         /* SetPixelFormat */
220                         if (state->writepos < (sizeof(struct pixel_format) + 4))
221                                 return NEEDMORE;
222                         outputf("RFB: SetPixelFormat");
223 /*
224                         struct pixel_format * new_fmt =
225                                 (struct pixel_format *)(&state->data[4]);
226 */
227                         /* XXX ... */
228
229                         state->readpos += sizeof(struct pixel_format) + 4;
230                         return OK;
231
232                 case SET_ENCODINGS:
233                         if (state->writepos < 4) return NEEDMORE;
234
235                         struct set_encs_req * req = (struct set_encs_req *)state->data;
236
237                         pktsize = sizeof(struct set_encs_req) + (4 * ntohs(req->num));
238
239                         outputf("RFB: SetEncodings [%d]", ntohs(req->num));
240                         if (state->writepos < pktsize) return NEEDMORE;
241
242                         for (i = 0; i < ntohs(req->num); i++) {
243                                 outputf("RFB: Encoding: %d", ntohl(req->encodings[i]));
244                                 /* XXX ... */
245
246                         }
247
248                         state->readpos += pktsize;
249                         return OK;
250
251                 case FB_UPDATE_REQUEST:
252                         if (state->writepos < sizeof(struct fb_update_req))
253                                 return NEEDMORE;
254                         outputf("RFB: UpdateRequest");
255
256                         state->update_allowed = 1;
257                         memcpy(&state->client_interest_area, state->data,
258                                sizeof(struct fb_update_req)); 
259
260                         state->readpos += sizeof(struct fb_update_req);
261                         return OK;
262
263                 case KEY_EVENT:
264                         if (state->writepos < sizeof(struct key_event_pkt))
265                                 return NEEDMORE;
266                         outputf("RFB: Key");
267
268                         /* XXX stub */
269
270                         state->readpos += sizeof(struct key_event_pkt);
271                         return OK;
272
273                 case POINTER_EVENT:
274                         if (state->writepos < sizeof(struct pointer_event_pkt))
275                                 return NEEDMORE;
276                         outputf("RFB: Pointer");
277
278                         /* XXX stub */
279
280                         state->readpos += sizeof(struct pointer_event_pkt);
281                         return OK;
282
283                 case CLIENT_CUT_TEXT:
284                         if (state->writepos < sizeof(struct text_event_pkt))
285                                 return NEEDMORE;
286                         outputf("RFB: Cut Text");
287
288                         struct text_event_pkt * pkt =
289                                 (struct text_event_pkt *)state->data;
290
291                         if (state->writepos < sizeof(struct text_event_pkt)
292                                               + pkt->length)
293                                 return NEEDMORE;
294
295                         /* XXX stub */
296
297                         state->readpos += sizeof(struct text_event_pkt)
298                                           + pkt->length;
299                         return OK;
300
301                 default:
302                         outputf("RFB: Bad command: %d", state->data[0]);
303                 }
304         default:
305                 outputf("RFB: Bad state");
306                 return FAIL;
307         }
308 }
309
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;
313
314         if (state == NULL) 
315
316         if (err != ERR_OK) {
317                 outputf("RFB: recv err %d", err);
318                 /* FIXME do something better here? */
319                 return ERR_OK;
320         }
321
322         if (p == NULL) {
323                 outputf("RFB: Connection closed");
324                 close_conn(pcb, state);
325                 return ERR_OK;
326         }
327
328         if (p->tot_len > (RFB_BUF_SIZE - state->writepos)) {
329                 /* Overflow! */
330                 outputf("RFB: Overflow!");
331                 close_conn(pcb, state);
332                 return ERR_OK;
333         }
334
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;
338
339         tcp_recved(pcb, p->tot_len);
340         pbuf_free(p);
341
342         while (1) {
343                 switch (recv_fsm(pcb, state)) {
344                 case NEEDMORE:
345                         outputf("RFB FSM: blocking");
346                         /* Need more data */
347                         return ERR_OK;
348
349                 case OK:
350                         outputf("RFB FSM: ok");
351
352                         /* Might as well send now... */
353                         if (state->update_allowed && !state->sending) {
354                                 start_send(pcb, state);
355                         }
356
357                         if (state->readpos == state->writepos) {
358                                 state->readpos = 0;
359                                 state->writepos = 0;
360                                 return ERR_OK;
361                         } else {
362                                 memmove(state->data,
363                                         state->data + state->readpos,
364                                         state->writepos - state->readpos);
365                         }
366                         break;
367                 case FAIL:
368                         /* Shit */
369                         outputf("RFB: Protocol error");
370                         close_conn(pcb, state);
371                         return ERR_OK;
372                 }
373         }
374 }       
375                 
376 static err_t rfb_accept(void *arg, struct tcp_pcb *pcb, err_t err) {
377         struct rfb_state *state;
378
379         LWIP_UNUSED_ARG(arg);
380         LWIP_UNUSED_ARG(err);
381
382         state = (struct rfb_state *)mem_malloc(sizeof(struct rfb_state));
383
384         state->state = ST_BEGIN;
385         state->readpos = 0;
386         state->writepos = 0;
387         state->update_allowed = 0;
388         state->sending = 0;
389
390         /* XXX: update_server_info() should be called from the 64ms timer, and deal
391          * with screen resizes appropriately. */
392         update_server_info();
393
394         if (!state)
395         {
396                 outputf("rfb_accept: out of memory\n");
397                 return ERR_MEM;
398         }
399
400         tcp_arg(pcb, state);
401         tcp_recv(pcb, rfb_recv);
402 /*
403         tcp_err(pcb, rfb_err);
404         tcp_poll(pcb, rfb_poll, 2);
405 */
406         tcp_write(pcb, "RFB 003.008\n", 12, 0);
407         tcp_output(pcb);
408
409         return ERR_OK;
410 }
411
412 void rfb_init() {
413         struct tcp_pcb *pcb;
414
415         init_server_info();
416
417         pcb = tcp_new();
418         tcp_bind(pcb, IP_ADDR_ANY, RFB_PORT);
419         pcb = tcp_listen(pcb);
420         tcp_accept(pcb, rfb_accept);
421 }
This page took 0.044008 seconds and 4 git commands to generate.