]> git.sesse.net Git - rdpsrv/blob - rdpsrv.c
Try to translate (very rudimentarily) RDP keycodes to VNC keysyms.
[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                         buf[0] = 5; // message type
145                         buf[1] = mouse1_down | mouse2_down; // button mask
146                         buf[2] = param1 >> 8;
147                         buf[3] = param1 & 0xff;
148                         buf[4] = param2 >> 8;
149                         buf[5] = param2 & 0xff;
150                         write(vnc_sock, buf, 6);
151                         
152                         break;
153                 default:
154                         printf("- Unknown type %x\n", message_type);
155                         break;
156                 }
157                 printf("\n");
158         }
159         
160         // re-request the entire framebuffer
161         buf[0] = 3; // message type
162         buf[1] = 1; // incremental
163         buf[2] = 0; // xpos
164         buf[3] = 0;
165         buf[4] = 0; // ypos
166         buf[5] = 0;
167         buf[6] = 640 >> 8; // width
168         buf[7] = 640 & 0xff;
169         buf[8] = 480 >> 8; // height
170         buf[9] = 480 & 0xff;
171
172         write(vnc_sock, buf, 10);
173 }
174
175 struct ServerInitialization {
176         unsigned short width;
177         unsigned short height;
178         unsigned char pixelformat[16]; // FIXME
179         unsigned int name_len;
180 };
181
182 int vnc_init()
183 {
184         char buf[256];
185         int vnc_sock = tcp_connect("127.0.0.1", 5901);
186         struct ServerInitialization si;
187
188         // get handshake
189         if (read(vnc_sock, buf, 12) != 12)
190                 error("short read on handshake\n");
191         write(vnc_sock, "RFB 003.003\n", 12);
192
193         // get auth
194         if (read(vnc_sock, buf, 4) != 4)
195                 error("short read on auth\n");
196
197         if (buf[3] != 1)
198                 error("auth needed or connection failed\n");
199
200         // send shared flag
201         buf[0] = 1;
202         write(vnc_sock, buf, 1);
203
204         // read the server initialization
205         if (read(vnc_sock, &si, sizeof(struct ServerInitialization)) != sizeof(struct ServerInitialization))
206                 error("short read on SI");
207
208         printf("Server is %u x %u\n", ntohs(si.width), ntohs(si.height));
209
210         if (read(vnc_sock, buf, ntohl(si.name_len)) != ntohl(si.name_len))
211                 error("short read on server name\n");
212
213 //      printf("Server name is '%*s' (%u bytes)\n", ntohl(si.name_len), buf, ntohl(si.name_len));
214
215         // we can only accept raw encoding
216         buf[0] = 2; // message type
217         buf[1] = 0; // padding
218         buf[2] = 0; // number of encodings
219         buf[3] = 1;
220         buf[4] = 0; // raw encoding
221         buf[5] = 0; 
222         buf[6] = 0;
223         buf[7] = 0;
224
225         write(vnc_sock, buf, 8);
226         
227         // request the entire framebuffer
228         buf[0] = 3; // message type
229         buf[1] = 0; // incremental
230         buf[2] = 0; // xpos
231         buf[3] = 0;
232         buf[4] = 0; // ypos
233         buf[5] = 0;
234         buf[6] = 640 >> 8; // width
235         buf[7] = 640 & 0xff;
236         buf[8] = 480 >> 8; // height
237         buf[9] = 480 & 0xff;
238
239         write(vnc_sock, buf, 10);
240         
241         printf("Connected to VNC!\n");
242
243         return vnc_sock;
244 }
245
246 struct vnc_rectangle {
247         unsigned short x, y, width, height;
248         unsigned int encoding;
249 };
250
251 void handle_vnc_fbupdate(int vnc_sock)
252 {
253         struct vnc_rectangle rect;
254         unsigned char *data, *ptr, *src, *dst;
255         unsigned short num_rect;
256         int ret, data_left, i, xt, yt;
257         unsigned char smallblock[64 * 64 * 3];
258
259         if (read(vnc_sock, &num_rect, 2) != 2)
260                 error("short read on num_rect\n");
261
262         for (i = 0; i < ntohs(num_rect); ++i) {
263                 int width, height;
264                 
265                 if (read(vnc_sock, &rect, sizeof(struct vnc_rectangle)) != sizeof(struct vnc_rectangle))
266                         error("short read on vnc_rectangle\n");
267                 
268                 if (ntohl(rect.encoding) != 0)
269                         error("unsupported encoding\n");
270
271                 width = ntohs(rect.width);
272                 height = ntohs(rect.height);
273                 
274                 printf("UPDATE: %ux%u at (%u,%u)\n", width, height,
275                         ntohs(rect.x), ntohs(rect.y));
276                 
277                 ptr = data = xmalloc(width * height * 4);
278                 data_left = width * height * 4;
279
280                 while (data_left > 0) {
281                         ret = read(vnc_sock, ptr, data_left);
282                         if (ret <= 0)
283                                 error("error on data read\n");
284
285                         ptr += ret;
286                         data_left -= ret;
287                 }
288
289                 // push our 32-bit RGB data into small enough chunks
290                 // (64x64) so we are sure we can send them without
291                 // everything crashing and stuff :-)
292                 for (yt = 0; yt < (height + 63) / 64; ++yt) {
293                         for (xt = 0; xt < (width + 63) / 64; ++xt) {
294                                 int x, y;
295                                 int bw = width - xt * 64;
296                                 int bh = height - yt * 64;
297                                 if (bw > 64)
298                                         bw = 64;
299                                 if (bh > 64)
300                                         bh = 64;
301                         
302                                 dst = smallblock;
303                                 for (y = 0; y < bh; ++y) {
304                                         src = data + ((yt * 64 + (bh - 1 - y)) * width + (xt * 64)) * 4;
305                                         for (x = 0; x < bw; ++x) {
306                                                 *dst++ = *src++;
307                                                 *dst++ = *src++;
308                                                 *dst++ = *src++;
309                                                 ++src;
310                                         }
311                                 }
312
313                                 rdp_send_bitmap_update(ntohs(rect.x) + xt * 64, ntohs(rect.y) + yt * 64, bw, bh, smallblock);
314                         }
315                 }
316                 
317                 xfree(data);
318         }
319 }
320
321 int serve_client()
322 {
323         int vnc_sock = vnc_init();
324         int listen_on_vnc = 0;
325         
326         if (!mcs_recv_connect_initial())
327                 error("MCS_CONNECT_INITIAL recv failed");
328         mcs_send_connect_response();
329
330         for ( ;; ) {
331                 uint8 type, data_pdu_type;
332                 STREAM s;
333
334                 fd_set readfs;
335                 FD_ZERO(&readfs);
336                 FD_SET(tcp_get_socket(), &readfs);
337                 FD_SET(vnc_sock, &readfs);
338                 
339                 select(FD_SETSIZE, &readfs, NULL, NULL, NULL);
340
341                 // activity on RDP socket?
342                 if (FD_ISSET(tcp_get_socket(), &readfs)) {
343                         if ((s = rdp_recv(&type)) != NULL) {
344                                 if (type != RDP_PDU_DATA) {
345                                         printf("Unknown RDP packet of type %u\n", type);
346                                         continue;
347                                 }
348
349                                 in_uint8s(s, 8);        /* shareid, pad, streamid, length */
350                                 in_uint8(s, data_pdu_type);
351                                 in_uint8s(s, 3);        /* compress_type, compress_len */
352
353                                 switch (data_pdu_type) {
354                                 case RDP_DATA_PDU_INPUT:
355                                         handle_input_pdu(s, vnc_sock);
356                                         listen_on_vnc = 1;
357                                         break;
358                                 default:
359                                         printf("Unknown data PDU type %u\n", data_pdu_type);
360                                 };
361                         }
362                 }
363
364                 // activity on VNC socket?
365                 if (FD_ISSET(vnc_sock, &readfs) && listen_on_vnc) {
366                         unsigned char buf[256];
367
368                         printf("Activity on VNC socket!\n");
369                         
370                         if (read(vnc_sock, buf, 1) != 1)
371                                 error("short read on vnc_sock\n");
372
373                         switch (buf[0]) {
374                         case 0:
375                                 // frame buffer update!
376                                 printf("Framebuffer update\n");
377                                 if (read(vnc_sock, buf, 1) != 1)
378                                         error("short read on vnc_sock\n");
379                                 handle_vnc_fbupdate(vnc_sock);
380                                 break;
381                         case 2: // bell
382                                 printf("\a\n");
383                                 break;
384                         case 3:
385                                 printf("New text in clipboard, ignoring\n");
386                                 if (read(vnc_sock, buf, 3) != 3)
387                                         error("short read on vnc_sock\n");
388                                 if (read(vnc_sock, buf, 4) != 4)
389                                         error("short read on vnc_sock\n");
390                                 if (read(vnc_sock, (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3], 4) != 4)
391                                         error("short read on vnc_sock\n");
392                                 
393                         default:
394                                 printf("Unknown VNC server message %x\n", buf[0]);
395                                 exit(1);
396                         }
397                 }
398         }
399 }