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