2 * FreeRDP: A Remote Desktop Protocol Client
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Copyright 2011 Vic Lee
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
28 #include <freerdp/constants.h>
29 #include <freerdp/utils/sleep.h>
30 #include <freerdp/utils/memory.h>
31 #include <freerdp/utils/thread.h>
32 #include <freerdp/codec/rfx.h>
33 #include <freerdp/listener.h>
34 #include <freerdp/channels/wtsvc.h>
36 static char* test_pcap_file = NULL;
37 static boolean test_dump_rfx_realtime = true;
39 /* HL1, LH1, HH1, HL2, LH2, HH2, HL3, LH3, HH3, LL3 */
40 static const unsigned int test_quantization_values[] =
42 6, 6, 6, 6, 7, 7, 8, 8, 8, 9
45 struct test_peer_context
49 RFX_CONTEXT* rfx_context;
58 WTSVirtualChannelManager* vcm;
60 freerdp_thread* debug_channel_thread;
62 typedef struct test_peer_context testPeerContext;
64 void test_peer_context_new(freerdp_peer* client, testPeerContext* context)
66 context->rfx_context = rfx_context_new();
67 context->rfx_context->mode = RLGR3;
68 context->rfx_context->width = client->settings->width;
69 context->rfx_context->height = client->settings->height;
70 rfx_context_set_pixel_format(context->rfx_context, RFX_PIXEL_FORMAT_RGB);
72 context->s = stream_new(65536);
77 context->vcm = WTSCreateVirtualChannelManager(client);
80 void test_peer_context_free(freerdp_peer* client, testPeerContext* context)
84 if (context->debug_channel_thread)
86 freerdp_thread_stop(context->debug_channel_thread);
87 freerdp_thread_free(context->debug_channel_thread);
89 stream_free(context->s);
90 xfree(context->icon_data);
91 xfree(context->bg_data);
92 rfx_context_free(context->rfx_context);
93 if (context->debug_channel)
95 WTSVirtualChannelClose(context->debug_channel);
97 WTSDestroyVirtualChannelManager(context->vcm);
102 static void test_peer_init(freerdp_peer* client)
104 client->context_size = sizeof(testPeerContext);
105 client->ContextNew = (psPeerContextNew) test_peer_context_new;
106 client->ContextFree = (psPeerContextFree) test_peer_context_free;
107 freerdp_peer_context_new(client);
110 static STREAM* test_peer_stream_init(testPeerContext* context)
112 stream_clear(context->s);
113 stream_set_pos(context->s, 0);
117 static void test_peer_draw_background(freerdp_peer* client)
119 testPeerContext* context = (testPeerContext*) client->context;
120 rdpUpdate* update = client->update;
121 SURFACE_BITS_COMMAND* cmd = &update->surface_bits_command;
127 if (!client->settings->rfx_codec)
130 s = test_peer_stream_init(context);
134 rect.width = client->settings->width;
135 rect.height = client->settings->height;
137 size = rect.width * rect.height * 3;
138 rgb_data = xmalloc(size);
139 memset(rgb_data, 0xA0, size);
141 rfx_compose_message(context->rfx_context, s,
142 &rect, 1, rgb_data, rect.width, rect.height, rect.width * 3);
146 cmd->destRight = rect.width;
147 cmd->destBottom = rect.height;
149 cmd->codecID = client->settings->rfx_codec_id;
150 cmd->width = rect.width;
151 cmd->height = rect.height;
152 cmd->bitmapDataLength = stream_get_length(s);
153 cmd->bitmapData = stream_get_head(s);
154 update->SurfaceBits(update->context, cmd);
159 static void test_peer_load_icon(freerdp_peer* client)
161 testPeerContext* context = (testPeerContext*) client->context;
168 if (!client->settings->rfx_codec)
171 if ((fp = fopen("test_icon.ppm", "r")) == NULL)
175 fgets(line, sizeof(line), fp);
176 /* Creater comment */
177 fgets(line, sizeof(line), fp);
179 fgets(line, sizeof(line), fp);
180 sscanf(line, "%d %d", &context->icon_width, &context->icon_height);
182 fgets(line, sizeof(line), fp);
184 rgb_data = xmalloc(context->icon_width * context->icon_height * 3);
186 for (i = 0; i < context->icon_width * context->icon_height * 3; i++)
188 if (fgets(line, sizeof(line), fp))
190 sscanf(line, "%d", &c);
191 rgb_data[i] = (uint8)c;
195 context->icon_data = rgb_data;
197 /* background with same size, which will be used to erase the icon from old position */
198 context->bg_data = xmalloc(context->icon_width * context->icon_height * 3);
199 memset(context->bg_data, 0xA0, context->icon_width * context->icon_height * 3);
202 static void test_peer_draw_icon(freerdp_peer* client, int x, int y)
204 testPeerContext* context = (testPeerContext*) client->context;
205 rdpUpdate* update = client->update;
206 SURFACE_BITS_COMMAND* cmd = &update->surface_bits_command;
210 if (client->update->dump_rfx)
212 if (!client->settings->rfx_codec || !context)
214 if (context->icon_width < 1 || !context->activated)
219 rect.width = context->icon_width;
220 rect.height = context->icon_height;
222 if (context->icon_x >= 0)
224 s = test_peer_stream_init(context);
225 rfx_compose_message(context->rfx_context, s,
226 &rect, 1, context->bg_data, rect.width, rect.height, rect.width * 3);
228 cmd->destLeft = context->icon_x;
229 cmd->destTop = context->icon_y;
230 cmd->destRight = context->icon_x + context->icon_width;
231 cmd->destBottom = context->icon_y + context->icon_height;
233 cmd->codecID = client->settings->rfx_codec_id;
234 cmd->width = context->icon_width;
235 cmd->height = context->icon_height;
236 cmd->bitmapDataLength = stream_get_length(s);
237 cmd->bitmapData = stream_get_head(s);
238 update->SurfaceBits(update->context, cmd);
241 s = test_peer_stream_init(context);
242 rfx_compose_message(context->rfx_context, s,
243 &rect, 1, context->icon_data, rect.width, rect.height, rect.width * 3);
247 cmd->destRight = x + context->icon_width;
248 cmd->destBottom = y + context->icon_height;
250 cmd->codecID = client->settings->rfx_codec_id;
251 cmd->width = context->icon_width;
252 cmd->height = context->icon_height;
253 cmd->bitmapDataLength = stream_get_length(s);
254 cmd->bitmapData = stream_get_head(s);
255 update->SurfaceBits(update->context, cmd);
261 static boolean test_sleep_tsdiff(uint32 *old_sec, uint32 *old_usec, uint32 new_sec, uint32 new_usec)
265 if (*old_sec==0 && *old_usec==0)
268 *old_usec = new_usec;
272 sec = new_sec - *old_sec;
273 usec = new_usec - *old_usec;
275 if (sec<0 || (sec==0 && usec<0))
277 printf("Invalid time stamp detected.\n");
282 *old_usec = new_usec;
294 freerdp_usleep(usec);
299 void tf_peer_dump_rfx(freerdp_peer* client)
303 uint32 prev_useconds;
309 update = client->update;
310 client->update->pcap_rfx = pcap_open(test_pcap_file, false);
311 pcap_rfx = client->update->pcap_rfx;
313 if (pcap_rfx == NULL)
316 prev_seconds = prev_useconds = 0;
318 while (pcap_has_next_record(pcap_rfx))
320 pcap_get_next_record_header(pcap_rfx, &record);
322 s->data = xrealloc(s->data, record.length);
323 record.data = s->data;
324 s->size = record.length;
326 pcap_get_next_record_content(pcap_rfx, &record);
327 s->p = s->data + s->size;
329 if (test_dump_rfx_realtime && test_sleep_tsdiff(&prev_seconds, &prev_useconds, record.header.ts_sec, record.header.ts_usec) == false)
332 update->SurfaceCommand(update->context, s);
336 static void* tf_debug_channel_thread_func(void* arg)
341 uint32 bytes_returned = 0;
342 testPeerContext* context = (testPeerContext*) arg;
343 freerdp_thread* thread = context->debug_channel_thread;
345 if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer, &bytes_returned) == true)
347 fd = *((void**)buffer);
348 WTSFreeMemory(buffer);
349 thread->signals[thread->num_signals++] = wait_obj_new_with_fd(fd);
352 s = stream_new(4096);
354 WTSVirtualChannelWrite(context->debug_channel, (uint8*) "test1", 5, NULL);
358 freerdp_thread_wait(thread);
359 if (freerdp_thread_is_stopped(thread))
362 stream_set_pos(s, 0);
363 if (WTSVirtualChannelRead(context->debug_channel, 0, stream_get_head(s),
364 stream_get_size(s), &bytes_returned) == false)
366 if (bytes_returned == 0)
368 stream_check_size(s, bytes_returned);
369 if (WTSVirtualChannelRead(context->debug_channel, 0, stream_get_head(s),
370 stream_get_size(s), &bytes_returned) == false)
372 /* should not happen */
376 stream_set_pos(s, bytes_returned);
378 printf("got %d bytes\n", bytes_returned);
382 freerdp_thread_quit(thread);
387 boolean tf_peer_post_connect(freerdp_peer* client)
390 testPeerContext* context = (testPeerContext*) client->context;
393 * This callback is called when the entire connection sequence is done, i.e. we've received the
394 * Font List PDU from the client and sent out the Font Map PDU.
395 * The server may start sending graphics output and receiving keyboard/mouse input after this
398 printf("Client %s is activated (osMajorType %d osMinorType %d)", client->hostname,
399 client->settings->os_major_type, client->settings->os_minor_type);
400 if (client->settings->autologon)
402 printf(" and wants to login automatically as %s\\%s",
403 client->settings->domain ? client->settings->domain : "",
404 client->settings->username);
406 /* A real server may perform OS login here if NLA is not executed previously. */
410 printf("Client requested desktop: %dx%dx%d\n",
411 client->settings->width, client->settings->height, client->settings->color_depth);
413 /* A real server should tag the peer as activated here and start sending updates in mainloop. */
414 test_peer_load_icon(client);
416 /* Iterate all channel names requested by the client and activate those supported by the server */
417 for (i = 0; i < client->settings->num_channels; i++)
419 if (client->settings->channels[i].joined)
421 if (strncmp(client->settings->channels[i].name, "rdpdbg", 6) == 0)
423 context->debug_channel = WTSVirtualChannelOpenEx(context->vcm, "rdpdbg", 0);
424 if (context->debug_channel != NULL)
426 printf("Open channel rdpdbg.\n");
427 context->debug_channel_thread = freerdp_thread_new();
428 freerdp_thread_start(context->debug_channel_thread,
429 tf_debug_channel_thread_func, context);
435 /* Return false here would stop the execution of the peer mainloop. */
439 boolean tf_peer_activate(freerdp_peer* client)
441 testPeerContext* context = (testPeerContext*) client->context;
443 rfx_context_reset(context->rfx_context);
444 context->activated = true;
446 if (test_pcap_file != NULL)
448 client->update->dump_rfx = true;
449 tf_peer_dump_rfx(client);
453 test_peer_draw_background(client);
459 void tf_peer_synchronize_event(rdpInput* input, uint32 flags)
461 printf("Client sent a synchronize event (flags:0x%X)\n", flags);
464 void tf_peer_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
466 freerdp_peer* client = input->context->peer;
467 rdpUpdate* update = client->update;
468 testPeerContext* context = (testPeerContext*) input->context;
470 printf("Client sent a keyboard event (flags:0x%X code:0x%X)\n", flags, code);
472 if ((flags & 0x4000) && code == 0x1F) /* 's' key */
474 if (client->settings->width != 800)
476 client->settings->width = 800;
477 client->settings->height = 600;
481 client->settings->width = 640;
482 client->settings->height = 480;
484 update->DesktopResize(update->context);
485 context->activated = false;
487 else if ((flags & 0x4000) && code == 0x2E) /* 'c' key */
489 if (context->debug_channel)
491 WTSVirtualChannelWrite(context->debug_channel, (uint8*) "test2", 5, NULL);
496 void tf_peer_unicode_keyboard_event(rdpInput* input, uint16 flags, uint16 code)
498 printf("Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code);
501 void tf_peer_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
503 printf("Client sent a mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y);
505 test_peer_draw_icon(input->context->peer, x + 10, y);
508 void tf_peer_extended_mouse_event(rdpInput* input, uint16 flags, uint16 x, uint16 y)
510 printf("Client sent an extended mouse event (flags:0x%X pos:%d,%d)\n", flags, x, y);
513 static void* test_peer_mainloop(void* arg)
521 testPeerContext* context;
522 freerdp_peer* client = (freerdp_peer*) arg;
524 memset(rfds, 0, sizeof(rfds));
526 test_peer_init(client);
528 /* Initialize the real server settings here */
529 client->settings->cert_file = xstrdup("server.crt");
530 client->settings->privatekey_file = xstrdup("server.key");
531 client->settings->nla_security = false;
532 client->settings->rfx_codec = true;
534 client->PostConnect = tf_peer_post_connect;
535 client->Activate = tf_peer_activate;
537 client->input->SynchronizeEvent = tf_peer_synchronize_event;
538 client->input->KeyboardEvent = tf_peer_keyboard_event;
539 client->input->UnicodeKeyboardEvent = tf_peer_unicode_keyboard_event;
540 client->input->MouseEvent = tf_peer_mouse_event;
541 client->input->ExtendedMouseEvent = tf_peer_extended_mouse_event;
543 client->Initialize(client);
544 context = (testPeerContext*) client->context;
546 printf("We've got a client %s\n", client->hostname);
552 if (client->GetFileDescriptor(client, rfds, &rcount) != true)
554 printf("Failed to get FreeRDP file descriptor\n");
557 WTSVirtualChannelManagerGetFileDescriptor(context->vcm, rfds, &rcount);
562 for (i = 0; i < rcount; i++)
564 fds = (int)(long)(rfds[i]);
569 FD_SET(fds, &rfds_set);
575 if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1)
577 /* these are not really errors */
578 if (!((errno == EAGAIN) ||
579 (errno == EWOULDBLOCK) ||
580 (errno == EINPROGRESS) ||
581 (errno == EINTR))) /* signal occurred */
583 printf("select failed\n");
588 if (client->CheckFileDescriptor(client) != true)
590 if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != true)
594 printf("Client %s disconnected.\n", client->hostname);
596 client->Disconnect(client);
597 freerdp_peer_context_free(client);
598 freerdp_peer_free(client);
603 static void test_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
607 pthread_create(&th, 0, test_peer_mainloop, client);
611 static void test_server_mainloop(freerdp_listener* instance)
620 memset(rfds, 0, sizeof(rfds));
626 if (instance->GetFileDescriptor(instance, rfds, &rcount) != true)
628 printf("Failed to get FreeRDP file descriptor\n");
635 for (i = 0; i < rcount; i++)
637 fds = (int)(long)(rfds[i]);
642 FD_SET(fds, &rfds_set);
648 if (select(max_fds + 1, &rfds_set, NULL, NULL, NULL) == -1)
650 /* these are not really errors */
651 if (!((errno == EAGAIN) ||
652 (errno == EWOULDBLOCK) ||
653 (errno == EINPROGRESS) ||
654 (errno == EINTR))) /* signal occurred */
656 printf("select failed\n");
661 if (instance->CheckFileDescriptor(instance) != true)
663 printf("Failed to check FreeRDP file descriptor\n");
668 instance->Close(instance);
671 int main(int argc, char* argv[])
673 freerdp_listener* instance;
675 /* Ignore SIGPIPE, otherwise an SSL_write failure could crash your server */
676 signal(SIGPIPE, SIG_IGN);
678 instance = freerdp_listener_new();
680 instance->PeerAccepted = test_peer_accepted;
683 test_pcap_file = argv[1];
685 if (argc > 2 && !strcmp(argv[2], "--fast"))
686 test_dump_rfx_realtime = false;
688 /* Open the server socket and start listening. */
689 if (instance->Open(instance, NULL, 3389))
691 /* Entering the server main loop. In a real server the listener can be run in its own thread. */
692 test_server_mainloop(instance);
695 freerdp_listener_free(instance);