1718dc1e30f169cfa52f4919bd6b6199dafbbab7
[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
118 struct ServerInitialization {
119         unsigned short width;
120         unsigned short height;
121         unsigned char pixelformat[16]; // FIXME
122         unsigned int name_len;
123 };
124
125 int vnc_init()
126 {
127         char buf[256];
128         int vnc_sock = tcp_connect("127.0.0.1", 5901);
129         struct ServerInitialization si;
130
131         // get handshake
132         if (read(vnc_sock, buf, 12) != 12)
133                 error("short read on handshake\n");
134         write(vnc_sock, "RFB 003.003\n", 12);
135
136         // get auth
137         if (read(vnc_sock, buf, 4) != 4)
138                 error("short read on auth\n");
139
140         if (buf[3] != 1)
141                 error("auth needed or connection failed\n");
142
143         // send shared flag
144         buf[0] = 1;
145         write(vnc_sock, buf, 1);
146
147         // read the server initialization
148         if (read(vnc_sock, &si, sizeof(struct ServerInitialization)) != sizeof(struct ServerInitialization))
149                 error("short read on SI");
150
151         printf("Server is %u x %u\n", ntohs(si.width), ntohs(si.height));
152
153         if (read(vnc_sock, buf, ntohl(si.name_len)) != ntohl(si.name_len))
154                 error("short read on server name\n");
155
156         printf("Server name is '%*s' (%u bytes)\n", ntohl(si.name_len), buf, ntohl(si.name_len));
157
158         // we can only accept raw encoding
159         buf[0] = 2; // message type
160         buf[1] = 0; // padding
161         buf[2] = 0; // number of encodings
162         buf[3] = 1;
163         buf[4] = 0; // raw encoding
164         buf[5] = 0; 
165         buf[6] = 0;
166         buf[7] = 0;
167
168         write(vnc_sock, buf, 8);
169         
170         // request the entire framebuffer
171         buf[0] = 3; // message type
172         buf[1] = 0; // incremental
173         buf[2] = 0; // xpos
174         buf[3] = 0;
175         buf[4] = 0; // ypos
176         buf[5] = 0;
177         buf[6] = 640 >> 8; // width
178         buf[7] = 640 & 0xff;
179         buf[8] = 480 >> 8; // height
180         buf[9] = 480 & 0xff;
181
182         write(vnc_sock, buf, 10);
183         
184         printf("Connected to VNC!\n");
185
186         return vnc_sock;
187 }
188
189 struct vnc_rectangle {
190         unsigned short x, y, width, height;
191         unsigned int encoding;
192 };
193
194 void handle_vnc_fbupdate(int vnc_sock)
195 {
196         struct vnc_rectangle rect;
197         unsigned char *data, *ptr, *src, *dst;
198         unsigned short num_rect;
199         int ret, data_left, i, xt, yt;
200         unsigned char smallblock[64 * 64 * 3];
201
202         if (read(vnc_sock, &num_rect, 2) != 2)
203                 error("short read on num_rect\n");
204
205         for (i = 0; i < ntohs(num_rect); ++i) {
206                 int width, height;
207                 
208                 if (read(vnc_sock, &rect, sizeof(struct vnc_rectangle)) != sizeof(struct vnc_rectangle))
209                         error("short read on vnc_rectangle\n");
210                 
211                 if (ntohl(rect.encoding) != 0)
212                         error("unsupported encoding\n");
213
214                 width = ntohs(rect.width);
215                 height = ntohs(rect.height);
216                 
217                 printf("UPDATE: %ux%u at (%u,%u)\n", width, height,
218                         ntohs(rect.x), ntohs(rect.y));
219                 
220                 ptr = data = xmalloc(width * height * 4);
221                 data_left = width * height * 4;
222
223                 while (data_left > 0) {
224                         ret = read(vnc_sock, ptr, data_left);
225                         if (ret <= 0)
226                                 error("error on data read\n");
227
228                         ptr += ret;
229                         data_left -= ret;
230                 }
231
232                 // push our 32-bit RGB data into small enough chunks
233                 // (64x64) so we are sure we can send them without
234                 // everything crashing and stuff :-)
235                 for (yt = 0; yt < (height + 63) / 64; ++yt) {
236                         for (xt = 0; xt < (width + 63) / 64; ++xt) {
237                                 int x, y;
238                                 int bw = width - xt * 64;
239                                 int bh = height - yt * 64;
240                                 if (bw > 64)
241                                         bw = 64;
242                                 if (bh > 64)
243                                         bh = 64;
244                         
245                                 dst = smallblock;
246                                 for (y = 0; y < bh; ++y) {
247                                         src = data + ((yt * 64 + (bh + 1 - y)) * width + (xt * 64)) * 4;
248                                         for (x = 0; x < bw; ++x) {
249                                                 *dst++ = *src++;
250                                                 *dst++ = *src++;
251                                                 *dst++ = *src++;
252                                                 ++src;
253                                         }
254                                 }
255
256                                 rdp_send_bitmap_update(ntohs(rect.x) + xt * 64, ntohs(rect.y) + yt * 64, bw, bh, smallblock);
257                         }
258                 }
259                 
260                 xfree(data);
261         }
262 }
263
264 int serve_client()
265 {
266         int vnc_sock = vnc_init();
267         int listen_on_vnc = 0;
268         
269         if (!mcs_recv_connect_initial())
270                 error("MCS_CONNECT_INITIAL recv failed");
271         mcs_send_connect_response();
272
273         for ( ;; ) {
274                 uint8 type, data_pdu_type;
275                 STREAM s;
276
277                 fd_set readfs;
278                 FD_ZERO(&readfs);
279                 FD_SET(tcp_get_socket(), &readfs);
280                 FD_SET(vnc_sock, &readfs);
281                 
282                 select(FD_SETSIZE, &readfs, NULL, NULL, NULL);
283
284                 // activity on RDP socket?
285                 if (FD_ISSET(tcp_get_socket(), &readfs)) {
286                         if ((s = rdp_recv(&type)) != NULL) {
287                                 if (type != RDP_PDU_DATA) {
288                                         printf("Unknown RDP packet of type %u\n", type);
289                                         continue;
290                                 }
291
292                                 in_uint8s(s, 8);        /* shareid, pad, streamid, length */
293                                 in_uint8(s, data_pdu_type);
294                                 in_uint8s(s, 3);        /* compress_type, compress_len */
295
296                                 switch (data_pdu_type) {
297                                 case RDP_DATA_PDU_INPUT:
298                                         handle_input_pdu(s, vnc_sock);
299                                         listen_on_vnc = 1;
300                                         break;
301                                 default:
302                                         printf("Unknown data PDU type %u\n", data_pdu_type);
303                                 };
304                         }
305                 }
306
307                 // activity on VNC socket?
308                 if (FD_ISSET(vnc_sock, &readfs) && listen_on_vnc) {
309                         unsigned char buf[256];
310
311                         printf("Activity on VNC socket!\n");
312                         
313                         if (read(vnc_sock, buf, 2) != 2)
314                                 error("short read on vnc_sock\n");
315
316                         switch (buf[0]) {
317                         case 0:
318                                 // frame buffer update!
319                                 handle_vnc_fbupdate(vnc_sock);
320                                 break;
321                         default:
322                                 printf("Unknown VNC server message %x\n", buf[0]);
323                                 exit(1);
324                         }
325                 }
326         }
327 }