]> git.sesse.net Git - rdpsrv/blob - rdpsrv.c
We have picture!
[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)
63 {
64         uint32 time;
65         uint16 message_type, device_flags, param1, param2;
66         uint16 num_events;
67         int i;
68
69         in_uint16_le(s, num_events);   // number of events
70         in_uint8s(s, 2);        // pad
71
72         for (i = 0; i < num_events; ++i) {
73                 rdp_recv_input(s, &time, &message_type, &device_flags, &param1, &param2);
74                 printf("Input event at time %u\n", time);
75                 
76                 switch (message_type) {
77                 case RDP_INPUT_SYNCHRONIZE:
78                         printf("- Type: Synchronize (ignored)\n");
79                         break;
80                 case RDP_INPUT_CODEPOINT:
81                         printf("- Type: Codepoint (ignored)\n");
82                         break;
83                 case RDP_INPUT_VIRTKEY:
84                         printf("- Type: Virtual key (ignored)\n");
85                         break;
86                 case RDP_INPUT_SCANCODE:
87                         printf("- Type: Scancode (ignored)\n");
88                         break;
89                 case RDP_INPUT_MOUSE:
90                         printf("- Type: Mouse\n");
91                         printf("- Device flags: %x\n", device_flags);
92                         printf("- Position: (%u,%u)\n", param1, param2);
93
94                         break;
95                 default:
96                         printf("- Unknown type %x\n", message_type);
97                         break;
98                 }
99                 printf("\n");
100         }
101 }
102
103 struct ServerInitialization {
104         unsigned short width;
105         unsigned short height;
106         unsigned char pixelformat[16]; // FIXME
107         unsigned int name_len;
108 };
109
110 int vnc_init()
111 {
112         char buf[256];
113         int vnc_sock = tcp_connect("127.0.0.1", 5901);
114         struct ServerInitialization si;
115
116         // get handshake
117         if (read(vnc_sock, buf, 12) != 12)
118                 error("short read on handshake\n");
119         write(vnc_sock, "RFB 003.003\n", 12);
120
121         // get auth
122         if (read(vnc_sock, buf, 4) != 4)
123                 error("short read on auth\n");
124
125         if (buf[3] != 1)
126                 error("auth needed or connection failed\n");
127
128         // send shared flag
129         buf[0] = 1;
130         write(vnc_sock, buf, 1);
131
132         // read the server initialization
133         if (read(vnc_sock, &si, sizeof(struct ServerInitialization)) != sizeof(struct ServerInitialization))
134                 error("short read on SI");
135
136         printf("Server is %u x %u\n", ntohs(si.width), ntohs(si.height));
137
138         if (read(vnc_sock, buf, ntohl(si.name_len)) != ntohl(si.name_len))
139                 error("short read on server name\n");
140
141         printf("Server name is '%*s' (%u bytes)\n", ntohl(si.name_len), buf, ntohl(si.name_len));
142
143         // we can only accept raw encoding
144         buf[0] = 2; // message type
145         buf[1] = 0; // padding
146         buf[2] = 0; // number of encodings
147         buf[3] = 1;
148         buf[4] = 0; // raw encoding
149         buf[5] = 0; 
150         buf[6] = 0;
151         buf[7] = 0;
152
153         write(vnc_sock, buf, 8);
154         
155         // request the entire framebuffer
156         buf[0] = 3; // message type
157         buf[1] = 0; // incremental
158         buf[2] = 0; // xpos
159         buf[3] = 0;
160         buf[4] = 0; // ypos
161         buf[5] = 0;
162         buf[6] = 640 >> 8; // width
163         buf[7] = 640 & 0xff;
164         buf[8] = 480 >> 8; // height
165         buf[9] = 480 & 0xff;
166
167         write(vnc_sock, buf, 10);
168         
169         printf("Connected to VNC!\n");
170
171         return vnc_sock;
172 }
173
174 struct vnc_rectangle {
175         unsigned short x, y, width, height;
176         unsigned int encoding;
177 };
178
179 void handle_vnc_fbupdate(int vnc_sock)
180 {
181         struct vnc_rectangle rect;
182         unsigned char *data, *ptr, *src, *dst;
183         unsigned short num_rect;
184         int ret, data_left, i, xt, yt;
185         unsigned char smallblock[64 * 64 * 3];
186
187         if (read(vnc_sock, &num_rect, 2) != 2)
188                 error("short read on num_rect\n");
189
190         for (i = 0; i < ntohs(num_rect); ++i) {
191                 int width, height;
192                 
193                 if (read(vnc_sock, &rect, sizeof(struct vnc_rectangle)) != sizeof(struct vnc_rectangle))
194                         error("short read on vnc_rectangle\n");
195                 
196                 if (ntohl(rect.encoding) != 0)
197                         error("unsupported encoding\n");
198
199                 width = ntohs(rect.width);
200                 height = ntohs(rect.height);
201                 
202                 printf("UPDATE: %ux%u at (%u,%u)\n", width, height,
203                         ntohs(rect.x), ntohs(rect.y));
204                 
205                 ptr = data = xmalloc(width * height * 4);
206                 data_left = width * height * 4;
207
208                 while (data_left > 0) {
209                         ret = read(vnc_sock, ptr, data_left);
210                         if (ret <= 0)
211                                 error("error on data read\n");
212
213                         ptr += ret;
214                         data_left -= ret;
215                 }
216
217                 // push our 32-bit RGB data into small enough chunks
218                 // (64x64) so we are sure we can send them without
219                 // everything crashing and stuff :-)
220                 for (yt = 0; yt < (height + 63) / 64; ++yt) {
221                         for (xt = 0; xt < (width + 63) / 64; ++xt) {
222                                 int x, y;
223                                 int bw = width - xt * 64;
224                                 int bh = height - yt * 64;
225                                 if (bw > 64)
226                                         bw = 64;
227                                 if (bh > 64)
228                                         bh = 64;
229                         
230                                 dst = smallblock;
231                                 for (y = 0; y < bh; ++y) {
232                                         src = data + ((yt * 64 + (bh + 1 - y)) * width + (xt * 64)) * 4;
233                                         for (x = 0; x < bw; ++x) {
234                                                 *dst++ = *src++;
235                                                 *dst++ = *src++;
236                                                 *dst++ = *src++;
237                                                 ++src;
238                                         }
239                                 }
240
241                                 rdp_send_bitmap_update(ntohs(rect.x) + xt * 64, ntohs(rect.y) + yt * 64, bw, bh, smallblock);
242                         }
243                 }
244                 
245                 xfree(data);
246         }
247 }
248
249 int serve_client()
250 {
251         int vnc_sock = vnc_init();
252         int listen_on_vnc = 0;
253         
254         if (!mcs_recv_connect_initial())
255                 error("MCS_CONNECT_INITIAL recv failed");
256         mcs_send_connect_response();
257
258         for ( ;; ) {
259                 uint8 type, data_pdu_type;
260                 STREAM s;
261
262                 fd_set readfs;
263                 FD_ZERO(&readfs);
264                 FD_SET(tcp_get_socket(), &readfs);
265                 FD_SET(vnc_sock, &readfs);
266                 
267                 select(FD_SETSIZE, &readfs, NULL, NULL, NULL);
268
269                 // activity on RDP socket?
270                 if (FD_ISSET(tcp_get_socket(), &readfs)) {
271                         if ((s = rdp_recv(&type)) != NULL) {
272                                 if (type != RDP_PDU_DATA) {
273                                         printf("Unknown RDP packet of type %u\n", type);
274                                         continue;
275                                 }
276
277                                 in_uint8s(s, 8);        /* shareid, pad, streamid, length */
278                                 in_uint8(s, data_pdu_type);
279                                 in_uint8s(s, 3);        /* compress_type, compress_len */
280
281                                 switch (data_pdu_type) {
282                                 case RDP_DATA_PDU_INPUT:
283                                         printf("Input PDU\n");
284                                         handle_input_pdu(s);
285                                         listen_on_vnc = 1;
286                                         break;
287                                 default:
288                                         printf("Unknown data PDU type %u\n", data_pdu_type);
289                                 };
290                         }
291                 }
292
293                 // activity on VNC socket?
294                 if (FD_ISSET(vnc_sock, &readfs) && listen_on_vnc) {
295                         unsigned char buf[256];
296
297                         printf("Activity on VNC socket!\n");
298                         
299                         if (read(vnc_sock, buf, 2) != 2)
300                                 error("short read on vnc_sock\n");
301
302                         switch (buf[0]) {
303                         case 0:
304                                 // frame buffer update!
305                                 handle_vnc_fbupdate(vnc_sock);
306                                 break;
307                         default:
308                                 printf("Unknown VNC server message %x\n", buf[0]);
309                                 exit(1);
310                         }
311                 }
312         }
313 }