]> git.sesse.net Git - rdpsrv/blob - rdpsrv.c
Valgrind fixes, re-request updates all the time.
[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
12 const int tcp_port_rdp = 3389;
13 int create_server_socket();
14 int serve_client();
15
16 int main()
17 {
18         int server_sock = create_server_socket();
19         for ( ;; ) {
20                 iso_recv_connect(server_sock);
21                 printf("Got connection.\n");
22                 serve_client();
23                 printf("Client closed.\n");
24         }
25 }
26
27 int create_server_socket()
28 {
29         int server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
30         const unsigned int one = 1, zero = 0;
31         struct sockaddr_in addr;
32         int err;
33
34         setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
35         ioctl(server_sock, FIONBIO, &zero);
36
37         addr.sin_family = AF_INET;
38         addr.sin_addr.s_addr = INADDR_ANY;
39         addr.sin_port = htons(tcp_port_rdp);
40
41         do {
42                 err = bind(server_sock, (struct sockaddr *)&addr, sizeof(struct sockaddr));
43
44                 if (err == -1) {
45                         perror("bind()");
46
47                         /* try to recover from recoverable errors... */
48                         if (errno == ENOMEM || errno == EADDRINUSE) {
49                                 puts("Waiting 1 sec before trying again...");
50                                 sleep(1);
51                         } else {
52                                 puts("Giving up.");
53                                 exit(1);
54                         }
55                 }
56         } while (err == -1);
57
58         listen(server_sock, 20);
59         return server_sock;
60 }
61
62 void handle_input_pdu(STREAM s, int vnc_sock)
63 {
64         uint32 time;
65         uint16 message_type, device_flags, param1, param2;
66         uint16 num_events;
67         int i;
68         char buf[256];
69         static int mouse1_down = 0, mouse2_down = 0;
70
71         in_uint16_le(s, num_events);   // number of events
72         in_uint8s(s, 2);        // pad
73
74         for (i = 0; i < num_events; ++i) {
75                 rdp_recv_input(s, &time, &message_type, &device_flags, &param1, &param2);
76                 printf("Input event at time %u\n", time);
77                 
78                 switch (message_type) {
79                 case RDP_INPUT_SYNCHRONIZE:
80                         printf("- Type: Synchronize (ignored)\n");
81                         break;
82                 case RDP_INPUT_CODEPOINT:
83                         printf("- Type: Codepoint (ignored)\n");
84                         break;
85                 case RDP_INPUT_VIRTKEY:
86                         printf("- Type: Virtual key (ignored)\n");
87                         break;
88                 case RDP_INPUT_SCANCODE:
89                         printf("- Type: Scancode (ignored)\n");
90                         break;
91                 case RDP_INPUT_MOUSE:
92                         printf("- Type: Mouse\n");
93                         printf("- Device flags: %x\n", device_flags);
94                         printf("- Position: (%u,%u)\n", param1, param2);
95
96                         if (device_flags & MOUSE_FLAG_BUTTON1)
97                                  mouse1_down = (device_flags & MOUSE_FLAG_DOWN) ? 0x01 : 0;
98                         if (device_flags & MOUSE_FLAG_BUTTON2)
99                                  mouse2_down = (device_flags & MOUSE_FLAG_DOWN) ? 0x02 : 0;
100                         
101                         buf[0] = 5; // message type
102                         buf[1] = mouse1_down | mouse2_down; // button mask
103                         buf[2] = param1 >> 8;
104                         buf[3] = param1 & 0xff;
105                         buf[4] = param2 >> 8;
106                         buf[5] = param2 & 0xff;
107                         write(vnc_sock, buf, 6);
108                         
109                         break;
110                 default:
111                         printf("- Unknown type %x\n", message_type);
112                         break;
113                 }
114                 printf("\n");
115         }
116         
117         // re-request the entire framebuffer
118         buf[0] = 3; // message type
119         buf[1] = 1; // incremental
120         buf[2] = 0; // xpos
121         buf[3] = 0;
122         buf[4] = 0; // ypos
123         buf[5] = 0;
124         buf[6] = 640 >> 8; // width
125         buf[7] = 640 & 0xff;
126         buf[8] = 480 >> 8; // height
127         buf[9] = 480 & 0xff;
128
129         write(vnc_sock, buf, 10);
130 }
131
132 struct ServerInitialization {
133         unsigned short width;
134         unsigned short height;
135         unsigned char pixelformat[16]; // FIXME
136         unsigned int name_len;
137 };
138
139 int vnc_init()
140 {
141         char buf[256];
142         int vnc_sock = tcp_connect("127.0.0.1", 5901);
143         struct ServerInitialization si;
144
145         // get handshake
146         if (read(vnc_sock, buf, 12) != 12)
147                 error("short read on handshake\n");
148         write(vnc_sock, "RFB 003.003\n", 12);
149
150         // get auth
151         if (read(vnc_sock, buf, 4) != 4)
152                 error("short read on auth\n");
153
154         if (buf[3] != 1)
155                 error("auth needed or connection failed\n");
156
157         // send shared flag
158         buf[0] = 1;
159         write(vnc_sock, buf, 1);
160
161         // read the server initialization
162         if (read(vnc_sock, &si, sizeof(struct ServerInitialization)) != sizeof(struct ServerInitialization))
163                 error("short read on SI");
164
165         printf("Server is %u x %u\n", ntohs(si.width), ntohs(si.height));
166
167         if (read(vnc_sock, buf, ntohl(si.name_len)) != ntohl(si.name_len))
168                 error("short read on server name\n");
169
170 //      printf("Server name is '%*s' (%u bytes)\n", ntohl(si.name_len), buf, ntohl(si.name_len));
171
172         // we can only accept raw encoding
173         buf[0] = 2; // message type
174         buf[1] = 0; // padding
175         buf[2] = 0; // number of encodings
176         buf[3] = 1;
177         buf[4] = 0; // raw encoding
178         buf[5] = 0; 
179         buf[6] = 0;
180         buf[7] = 0;
181
182         write(vnc_sock, buf, 8);
183         
184         // request the entire framebuffer
185         buf[0] = 3; // message type
186         buf[1] = 0; // incremental
187         buf[2] = 0; // xpos
188         buf[3] = 0;
189         buf[4] = 0; // ypos
190         buf[5] = 0;
191         buf[6] = 640 >> 8; // width
192         buf[7] = 640 & 0xff;
193         buf[8] = 480 >> 8; // height
194         buf[9] = 480 & 0xff;
195
196         write(vnc_sock, buf, 10);
197         
198         printf("Connected to VNC!\n");
199
200         return vnc_sock;
201 }
202
203 struct vnc_rectangle {
204         unsigned short x, y, width, height;
205         unsigned int encoding;
206 };
207
208 void handle_vnc_fbupdate(int vnc_sock)
209 {
210         struct vnc_rectangle rect;
211         unsigned char *data, *ptr, *src, *dst;
212         unsigned short num_rect;
213         int ret, data_left, i, xt, yt;
214         unsigned char smallblock[64 * 64 * 3];
215
216         if (read(vnc_sock, &num_rect, 2) != 2)
217                 error("short read on num_rect\n");
218
219         for (i = 0; i < ntohs(num_rect); ++i) {
220                 int width, height;
221                 
222                 if (read(vnc_sock, &rect, sizeof(struct vnc_rectangle)) != sizeof(struct vnc_rectangle))
223                         error("short read on vnc_rectangle\n");
224                 
225                 if (ntohl(rect.encoding) != 0)
226                         error("unsupported encoding\n");
227
228                 width = ntohs(rect.width);
229                 height = ntohs(rect.height);
230                 
231                 printf("UPDATE: %ux%u at (%u,%u)\n", width, height,
232                         ntohs(rect.x), ntohs(rect.y));
233                 
234                 ptr = data = xmalloc(width * height * 4);
235                 data_left = width * height * 4;
236
237                 while (data_left > 0) {
238                         ret = read(vnc_sock, ptr, data_left);
239                         if (ret <= 0)
240                                 error("error on data read\n");
241
242                         ptr += ret;
243                         data_left -= ret;
244                 }
245
246                 // push our 32-bit RGB data into small enough chunks
247                 // (64x64) so we are sure we can send them without
248                 // everything crashing and stuff :-)
249                 for (yt = 0; yt < (height + 63) / 64; ++yt) {
250                         for (xt = 0; xt < (width + 63) / 64; ++xt) {
251                                 int x, y;
252                                 int bw = width - xt * 64;
253                                 int bh = height - yt * 64;
254                                 if (bw > 64)
255                                         bw = 64;
256                                 if (bh > 64)
257                                         bh = 64;
258                         
259                                 dst = smallblock;
260                                 for (y = 0; y < bh; ++y) {
261                                         src = data + ((yt * 64 + (bh - 1 - y)) * width + (xt * 64)) * 4;
262                                         for (x = 0; x < bw; ++x) {
263                                                 *dst++ = *src++;
264                                                 *dst++ = *src++;
265                                                 *dst++ = *src++;
266                                                 ++src;
267                                         }
268                                 }
269
270                                 rdp_send_bitmap_update(ntohs(rect.x) + xt * 64, ntohs(rect.y) + yt * 64, bw, bh, smallblock);
271                         }
272                 }
273                 
274                 xfree(data);
275         }
276 }
277
278 int serve_client()
279 {
280         int vnc_sock = vnc_init();
281         int listen_on_vnc = 0;
282         
283         if (!mcs_recv_connect_initial())
284                 error("MCS_CONNECT_INITIAL recv failed");
285         mcs_send_connect_response();
286
287         for ( ;; ) {
288                 uint8 type, data_pdu_type;
289                 STREAM s;
290
291                 fd_set readfs;
292                 FD_ZERO(&readfs);
293                 FD_SET(tcp_get_socket(), &readfs);
294                 FD_SET(vnc_sock, &readfs);
295                 
296                 select(FD_SETSIZE, &readfs, NULL, NULL, NULL);
297
298                 // activity on RDP socket?
299                 if (FD_ISSET(tcp_get_socket(), &readfs)) {
300                         if ((s = rdp_recv(&type)) != NULL) {
301                                 if (type != RDP_PDU_DATA) {
302                                         printf("Unknown RDP packet of type %u\n", type);
303                                         continue;
304                                 }
305
306                                 in_uint8s(s, 8);        /* shareid, pad, streamid, length */
307                                 in_uint8(s, data_pdu_type);
308                                 in_uint8s(s, 3);        /* compress_type, compress_len */
309
310                                 switch (data_pdu_type) {
311                                 case RDP_DATA_PDU_INPUT:
312                                         handle_input_pdu(s, vnc_sock);
313                                         listen_on_vnc = 1;
314                                         break;
315                                 default:
316                                         printf("Unknown data PDU type %u\n", data_pdu_type);
317                                 };
318                         }
319                 }
320
321                 // activity on VNC socket?
322                 if (FD_ISSET(vnc_sock, &readfs) && listen_on_vnc) {
323                         unsigned char buf[256];
324
325                         printf("Activity on VNC socket!\n");
326                         
327                         if (read(vnc_sock, buf, 1) != 1)
328                                 error("short read on vnc_sock\n");
329
330                         switch (buf[0]) {
331                         case 0:
332                                 // frame buffer update!
333                                 printf("Framebuffer update\n");
334                                 if (read(vnc_sock, buf, 1) != 1)
335                                         error("short read on vnc_sock\n");
336                                 handle_vnc_fbupdate(vnc_sock);
337                                 break;
338                         case 2:
339                                 printf("\a\n");
340                                 break;
341                         default:
342                                 printf("Unknown VNC server message %x\n", buf[0]);
343                                 exit(1);
344                         }
345                 }
346         }
347 }