]> git.sesse.net Git - rdpsrv/blob - rdpsrv.c
Send the same value back in synchronise.
[rdpsrv] / rdpsrv.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <sys/select.h>
6 #include <sys/socket.h>
7 #include <sys/ioctl.h>
8 #include <arpa/inet.h>
9
10 #include "rdesktop.h"
11 #include "scancodes.h"
12
13 const int tcp_port_rdp = 3389;
14 int create_server_socket();
15 int serve_client();
16
17 int main()
18 {
19         int server_sock = create_server_socket();
20         for ( ;; ) {
21                 iso_recv_connect(server_sock);
22                 printf("Got connection.\n");
23                 serve_client();
24                 printf("Client closed.\n");
25         }
26 }
27
28 int create_server_socket()
29 {
30         int server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
31         const unsigned int one = 1, zero = 0;
32         struct sockaddr_in addr;
33         int err;
34
35         setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
36         ioctl(server_sock, FIONBIO, &zero);
37
38         addr.sin_family = AF_INET;
39         addr.sin_addr.s_addr = INADDR_ANY;
40         addr.sin_port = htons(tcp_port_rdp);
41
42         do {
43                 err = bind(server_sock, (struct sockaddr *)&addr, sizeof(struct sockaddr));
44
45                 if (err == -1) {
46                         perror("bind()");
47
48                         /* try to recover from recoverable errors... */
49                         if (errno == ENOMEM || errno == EADDRINUSE) {
50                                 puts("Waiting 1 sec before trying again...");
51                                 sleep(1);
52                         } else {
53                                 puts("Giving up.");
54                                 exit(1);
55                         }
56                 }
57         } while (err == -1);
58
59         listen(server_sock, 20);
60         return server_sock;
61 }
62                         
63 int map_scancode_to_vnc_key(int scancode)
64 {
65         switch (scancode)
66         {
67         case SCANCODE_CHAR_1 ... SCANCODE_CHAR_9:
68                 return scancode + '1' - SCANCODE_CHAR_1;
69         case SCANCODE_CHAR_0:
70                 return '0';
71         case SCANCODE_CHAR_BACKSPACE:
72                 return 0xff08;
73         case SCANCODE_CHAR_TAB:
74                 return 0xff09;
75         case SCANCODE_CHAR_Q ... SCANCODE_CHAR_P:
76                 return "QWERTYUIOP"[scancode - SCANCODE_CHAR_Q];
77         case SCANCODE_CHAR_A ... SCANCODE_CHAR_L:
78                 return "ASDFGHJKL"[scancode - SCANCODE_CHAR_A];
79         case SCANCODE_CHAR_Z ... SCANCODE_CHAR_M:
80                 return "ZXCVBNM"[scancode - SCANCODE_CHAR_Z];
81         default:
82                 printf("Unknown scancode %x, ignoring\n", scancode);
83                 return -1;
84         }
85 }
86
87 void handle_input_pdu(STREAM s, int vnc_sock)
88 {
89         uint32 time;
90         uint16 message_type, device_flags, param1, param2;
91         uint16 num_events;
92         int i;
93         char buf[256];
94         static int mouse1_down = 0, mouse2_down = 0;
95         int vnc_key;
96
97         in_uint16_le(s, num_events);   // number of events
98         in_uint8s(s, 2);        // pad
99
100         for (i = 0; i < num_events; ++i) {
101                 rdp_recv_input(s, &time, &message_type, &device_flags, &param1, &param2);
102                 printf("Input event at time %u\n", time);
103                 
104                 switch (message_type) {
105                 case RDP_INPUT_SYNCHRONIZE:
106                         printf("- Type: Synchronize (ignored)\n");
107                         break;
108                 case RDP_INPUT_CODEPOINT:
109                         printf("- Type: Codepoint (ignored)\n");
110                         break;
111                 case RDP_INPUT_VIRTKEY:
112                         printf("- Type: Virtual key (ignored)\n");
113                         break;
114                 case RDP_INPUT_SCANCODE:
115                         printf("- Type: Scancode\n");
116                         printf("- Device flags: %x\n", device_flags);
117                         printf("- Key: %x\n", param1);
118                         
119                         vnc_key = map_scancode_to_vnc_key(param1);
120                         
121                         if (vnc_key != -1) {
122                                 buf[0] = 4; // message type
123                                 buf[1] = (device_flags & KBD_FLAG_DOWN) ? 1 : 0; // down flag
124                                 buf[2] = 0; // padding
125                                 buf[3] = 0;
126                                 buf[4] = vnc_key >> 24;  // keysym
127                                 buf[5] = (vnc_key >> 16) & 0xff;
128                                 buf[6] = (vnc_key >> 8) & 0xff;
129                                 buf[7] = vnc_key & 0xff;
130                                 write(vnc_sock, buf, 8);
131                         }
132                         
133                         break;
134                 case RDP_INPUT_MOUSE:
135                         printf("- Type: Mouse\n");
136                         printf("- Device flags: %x\n", device_flags);
137                         printf("- Position: (%u,%u)\n", param1, param2);
138
139                         if (device_flags & MOUSE_FLAG_BUTTON1)
140                                  mouse1_down = (device_flags & MOUSE_FLAG_DOWN) ? 0x01 : 0;
141                         if (device_flags & MOUSE_FLAG_BUTTON2)
142                                  mouse2_down = (device_flags & MOUSE_FLAG_DOWN) ? 0x02 : 0;
143                 
144                         printf("button mask = %x\n", mouse1_down | mouse2_down);
145                         
146                         buf[0] = 5; // message type
147                         buf[1] = mouse1_down | mouse2_down; // button mask
148                         buf[2] = param1 >> 8;
149                         buf[3] = param1 & 0xff;
150                         buf[4] = param2 >> 8;
151                         buf[5] = param2 & 0xff;
152                         write(vnc_sock, buf, 6);
153                         
154                         break;
155                 default:
156                         printf("- Unknown type %x\n", message_type);
157                         break;
158                 }
159                 printf("\n");
160         }
161         
162         // re-request the entire framebuffer
163         buf[0] = 3; // message type
164         buf[1] = 1; // incremental
165         buf[2] = 0; // xpos
166         buf[3] = 0;
167         buf[4] = 0; // ypos
168         buf[5] = 0;
169         buf[6] = 640 >> 8; // width
170         buf[7] = 640 & 0xff;
171         buf[8] = 480 >> 8; // height
172         buf[9] = 480 & 0xff;
173
174         write(vnc_sock, buf, 10);
175 }
176
177 void handle_control_pdu(STREAM s)
178 {
179         uint16 action, userid;
180         uint32 control_id;
181
182         in_uint16_le(s, action);
183         in_uint16_le(s, userid);
184         in_uint32(s, control_id);
185         
186         printf("Control PDU: action=%hu userid=%hu control_id=%u\n", action, userid, control_id);
187
188         switch (action) {
189         case RDP_CTL_COOPERATE:
190                 printf("Cooperate\n");
191                 rdp_send_control(RDP_CTL_COOPERATE);
192                 break;
193         case RDP_CTL_REQUEST_CONTROL:
194                 printf("Client requesting control; granting\n");
195                 rdp_send_control(RDP_CTL_GRANT_CONTROL);
196                 break;
197         default:
198                 printf("Unhandled\n");
199         }
200 }
201
202 struct ServerInitialization {
203         unsigned short width;
204         unsigned short height;
205         unsigned char pixelformat[16]; // FIXME
206         unsigned int name_len;
207 };
208
209 int vnc_init()
210 {
211         char buf[256];
212         int vnc_sock = tcp_connect("127.0.0.1", 5901);
213         struct ServerInitialization si;
214
215         // get handshake
216         if (read(vnc_sock, buf, 12) != 12)
217                 error("short read on handshake\n");
218         write(vnc_sock, "RFB 003.003\n", 12);
219
220         // get auth
221         if (read(vnc_sock, buf, 4) != 4)
222                 error("short read on auth\n");
223
224         if (buf[3] != 1)
225                 error("auth needed or connection failed\n");
226
227         // send shared flag
228         buf[0] = 1;
229         write(vnc_sock, buf, 1);
230
231         // read the server initialization
232         if (read(vnc_sock, &si, sizeof(struct ServerInitialization)) != sizeof(struct ServerInitialization))
233                 error("short read on SI");
234
235         printf("Server is %u x %u\n", ntohs(si.width), ntohs(si.height));
236
237         if (read(vnc_sock, buf, ntohl(si.name_len)) != ntohl(si.name_len))
238                 error("short read on server name\n");
239
240 //      printf("Server name is '%*s' (%u bytes)\n", ntohl(si.name_len), buf, ntohl(si.name_len));
241
242         // we can only accept raw encoding
243         buf[0] = 2; // message type
244         buf[1] = 0; // padding
245         buf[2] = 0; // number of encodings
246         buf[3] = 1;
247         buf[4] = 0; // raw encoding
248         buf[5] = 0; 
249         buf[6] = 0;
250         buf[7] = 0;
251
252         write(vnc_sock, buf, 8);
253         
254         // request the entire framebuffer
255         buf[0] = 3; // message type
256         buf[1] = 0; // incremental
257         buf[2] = 0; // xpos
258         buf[3] = 0;
259         buf[4] = 0; // ypos
260         buf[5] = 0;
261         buf[6] = 640 >> 8; // width
262         buf[7] = 640 & 0xff;
263         buf[8] = 480 >> 8; // height
264         buf[9] = 480 & 0xff;
265
266         write(vnc_sock, buf, 10);
267         
268         printf("Connected to VNC!\n");
269
270         return vnc_sock;
271 }
272
273 struct vnc_rectangle {
274         unsigned short x, y, width, height;
275         unsigned int encoding;
276 };
277
278 void handle_vnc_fbupdate(int vnc_sock)
279 {
280         struct vnc_rectangle rect;
281         unsigned char *data, *ptr, *src, *dst;
282         unsigned short num_rect;
283         int ret, data_left, i, xt, yt;
284         unsigned char smallblock[64 * 64 * 3];
285
286         if (read(vnc_sock, &num_rect, 2) != 2)
287                 error("short read on num_rect\n");
288
289         for (i = 0; i < ntohs(num_rect); ++i) {
290                 int width, height;
291                 
292                 if (read(vnc_sock, &rect, sizeof(struct vnc_rectangle)) != sizeof(struct vnc_rectangle))
293                         error("short read on vnc_rectangle\n");
294                 
295                 if (ntohl(rect.encoding) != 0)
296                         error("unsupported encoding\n");
297
298                 width = ntohs(rect.width);
299                 height = ntohs(rect.height);
300                 
301                 printf("UPDATE: %ux%u at (%u,%u)\n", width, height,
302                         ntohs(rect.x), ntohs(rect.y));
303                 
304                 ptr = data = xmalloc(width * height * 4);
305                 data_left = width * height * 4;
306
307                 while (data_left > 0) {
308                         ret = read(vnc_sock, ptr, data_left);
309                         if (ret <= 0)
310                                 error("error on data read\n");
311
312                         ptr += ret;
313                         data_left -= ret;
314                 }
315
316                 // push our 32-bit RGB data into small enough chunks
317                 // (64x64) so we are sure we can send them without
318                 // everything crashing and stuff :-)
319                 for (yt = 0; yt < (height + 63) / 64; ++yt) {
320                         for (xt = 0; xt < (width + 63) / 64; ++xt) {
321                                 int x, y;
322                                 int bw = width - xt * 64;
323                                 int bh = height - yt * 64;
324                                 if (bw > 64)
325                                         bw = 64;
326                                 if (bh > 64)
327                                         bh = 64;
328                         
329                                 dst = smallblock;
330                                 for (y = 0; y < bh; ++y) {
331                                         src = data + ((yt * 64 + (bh - 1 - y)) * width + (xt * 64)) * 4;
332                                         for (x = 0; x < bw; ++x) {
333                                                 *dst++ = *src++;
334                                                 *dst++ = *src++;
335                                                 *dst++ = *src++;
336                                                 ++src;
337                                         }
338                                 }
339
340                                 rdp_send_bitmap_update(ntohs(rect.x) + xt * 64, ntohs(rect.y) + yt * 64, bw, bh, smallblock);
341                         }
342                 }
343                 
344                 xfree(data);
345         }
346 }
347
348 int listen_on_vnc = 0;
349
350 int serve_client()
351 {
352         int vnc_sock = vnc_init();
353         
354         if (!mcs_recv_connect_initial())
355                 error("MCS_CONNECT_INITIAL recv failed");
356         mcs_send_connect_response();
357
358         for ( ;; ) {
359                 uint8 type, data_pdu_type;
360                 uint16 id;
361                 STREAM s;
362
363                 fd_set readfs;
364                 FD_ZERO(&readfs);
365                 FD_SET(tcp_get_socket(), &readfs);
366                 FD_SET(vnc_sock, &readfs);
367                 
368                 select(FD_SETSIZE, &readfs, NULL, NULL, NULL);
369
370                 // activity on RDP socket?
371                 if (FD_ISSET(tcp_get_socket(), &readfs)) {
372                         if ((s = rdp_recv(&type)) != NULL) {
373                                 switch (type) {
374                                 case RDP_PDU_DATA:
375                                         in_uint8s(s, 8);        /* shareid, pad, streamid, length */
376                                         in_uint8(s, data_pdu_type);
377                                         in_uint8s(s, 3);        /* compress_type, compress_len */
378
379                                         switch (data_pdu_type) {
380                                         case RDP_DATA_PDU_INPUT:
381                                                 handle_input_pdu(s, vnc_sock);
382                                                 listen_on_vnc = 1;
383                                                 break;
384                                         case RDP_DATA_PDU_CONTROL:
385                                                 handle_control_pdu(s);
386                                                 break;
387                                         case RDP_DATA_PDU_SYNCHRONISE:
388                                                 in_uint16_le(s, id);
389                                                 printf("Synchronise, id=%u\n", id);
390                                                 rdp_send_synchronise(id);
391                                                 break;
392                                         case RDP_DATA_PDU_FONT2:
393                                                 // respond with the
394                                                 // unknown 0x28 PDU
395                                                 // here?
396                                                 printf("FONT2, ignored\n");
397                                                 break;
398                                         default:
399                                                 printf("Unknown data PDU type %u\n", data_pdu_type);
400                                         };
401                                         break;
402                                 case RDP_PDU_CONFIRM_ACTIVE:
403                                         printf("Client confirms activity\n");
404                                         break;
405                                 default:
406                                         printf("Unknown RDP PDU type %u\n", type);
407                                 }
408                         }
409                 }
410
411                 // activity on VNC socket?
412                 if (FD_ISSET(vnc_sock, &readfs) && listen_on_vnc) {
413                         unsigned char buf[256];
414
415                         printf("Activity on VNC socket!\n");
416                         
417                         if (read(vnc_sock, buf, 1) != 1)
418                                 error("short read on vnc_sock\n");
419
420                         switch (buf[0]) {
421                         case 0:
422                                 // frame buffer update!
423                                 printf("Framebuffer update\n");
424                                 if (read(vnc_sock, buf, 1) != 1)
425                                         error("short read on vnc_sock\n");
426                                 handle_vnc_fbupdate(vnc_sock);
427                                 break;
428                         case 2: // bell
429                                 printf("\a\n");
430                                 break;
431                         case 3:
432                                 printf("New text in clipboard, ignoring\n");
433                                 if (read(vnc_sock, buf, 3) != 3)
434                                         error("short read on vnc_sock\n");
435                                 if (read(vnc_sock, buf, 4) != 4)
436                                         error("short read on vnc_sock\n");
437                                 if (read(vnc_sock, buf, (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]) != 4)
438                                         error("short read on vnc_sock\n");
439                                 
440                         default:
441                                 printf("Unknown VNC server message %x\n", buf[0]);
442                                 exit(1);
443                         }
444                 }
445         }
446 }