1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * FreeRDP Test Server
4 *
5 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6 * Copyright 2011 Vic Lee
7 * Copyright 2014 Norbert Federa <norbert.federa@thincast.com>
8 *
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <errno.h>
27 #include <signal.h>
28
29 #include <winpr/crt.h>
30 #include <winpr/ssl.h>
31 #include <winpr/synch.h>
32 #include <winpr/file.h>
33 #include <winpr/string.h>
34 #include <winpr/path.h>
35 #include <winpr/winsock.h>
36
37 #include <freerdp/channels/wtsvc.h>
38 #include <freerdp/channels/channels.h>
39
40 #include <freerdp/constants.h>
41 #include <freerdp/server/rdpsnd.h>
42
43 #include "sf_audin.h"
44 #include "sf_rdpsnd.h"
45 #include "sf_encomsp.h"
46
47 #include "sfreerdp.h"
48
49 #include <freerdp/log.h>
50 #define TAG SERVER_TAG("sample")
51
52 #define SAMPLE_SERVER_USE_CLIENT_RESOLUTION 1
53 #define SAMPLE_SERVER_DEFAULT_WIDTH 1024
54 #define SAMPLE_SERVER_DEFAULT_HEIGHT 768
55
56 static char* test_pcap_file = NULL;
57 static BOOL test_dump_rfx_realtime = TRUE;
58
test_peer_context_new(freerdp_peer * client,rdpContext * ctx)59 static BOOL test_peer_context_new(freerdp_peer* client, rdpContext* ctx)
60 {
61 testPeerContext* context = (testPeerContext*)ctx;
62 if (!(context->rfx_context = rfx_context_new(TRUE)))
63 goto fail_rfx_context;
64
65 if (!rfx_context_reset(context->rfx_context, SAMPLE_SERVER_DEFAULT_WIDTH,
66 SAMPLE_SERVER_DEFAULT_HEIGHT))
67 goto fail_rfx_context;
68
69 context->rfx_context->mode = RLGR3;
70 rfx_context_set_pixel_format(context->rfx_context, PIXEL_FORMAT_RGB24);
71
72 if (!(context->nsc_context = nsc_context_new()))
73 goto fail_nsc_context;
74
75 if (!nsc_context_set_parameters(context->nsc_context, NSC_COLOR_FORMAT, PIXEL_FORMAT_RGB24))
76 goto fail_stream_new;
77
78 if (!(context->s = Stream_New(NULL, 65536)))
79 goto fail_stream_new;
80
81 context->icon_x = -1;
82 context->icon_y = -1;
83 context->vcm = WTSOpenServerA((LPSTR)client->context);
84
85 if (!context->vcm || context->vcm == INVALID_HANDLE_VALUE)
86 goto fail_open_server;
87
88 return TRUE;
89 fail_open_server:
90 context->vcm = NULL;
91 Stream_Free(context->s, TRUE);
92 context->s = NULL;
93 fail_stream_new:
94 nsc_context_free(context->nsc_context);
95 context->nsc_context = NULL;
96 fail_nsc_context:
97 rfx_context_free(context->rfx_context);
98 context->rfx_context = NULL;
99 fail_rfx_context:
100 return FALSE;
101 }
102
test_peer_context_free(freerdp_peer * client,rdpContext * ctx)103 static void test_peer_context_free(freerdp_peer* client, rdpContext* ctx)
104 {
105 testPeerContext* context = (testPeerContext*)ctx;
106 WINPR_UNUSED(client);
107
108 if (context)
109 {
110 if (context->debug_channel_thread)
111 {
112 SetEvent(context->stopEvent);
113 WaitForSingleObject(context->debug_channel_thread, INFINITE);
114 CloseHandle(context->debug_channel_thread);
115 }
116
117 Stream_Free(context->s, TRUE);
118 free(context->icon_data);
119 free(context->bg_data);
120 rfx_context_free(context->rfx_context);
121 nsc_context_free(context->nsc_context);
122
123 if (context->debug_channel)
124 WTSVirtualChannelClose(context->debug_channel);
125
126 sf_peer_audin_uninit(context);
127
128 if (context->rdpsnd)
129 rdpsnd_server_context_free(context->rdpsnd);
130
131 if (context->encomsp)
132 encomsp_server_context_free(context->encomsp);
133
134 WTSCloseServer((HANDLE)context->vcm);
135 }
136 }
137
test_peer_init(freerdp_peer * client)138 static BOOL test_peer_init(freerdp_peer* client)
139 {
140 client->ContextSize = sizeof(testPeerContext);
141 client->ContextNew = test_peer_context_new;
142 client->ContextFree = test_peer_context_free;
143 return freerdp_peer_context_new(client);
144 }
145
test_peer_stream_init(testPeerContext * context)146 static wStream* test_peer_stream_init(testPeerContext* context)
147 {
148 Stream_Clear(context->s);
149 Stream_SetPosition(context->s, 0);
150 return context->s;
151 }
152
test_peer_begin_frame(freerdp_peer * client)153 static void test_peer_begin_frame(freerdp_peer* client)
154 {
155 rdpUpdate* update = client->update;
156 SURFACE_FRAME_MARKER fm = { 0 };
157 testPeerContext* context = (testPeerContext*)client->context;
158 fm.frameAction = SURFACECMD_FRAMEACTION_BEGIN;
159 fm.frameId = context->frame_id;
160 update->SurfaceFrameMarker(update->context, &fm);
161 }
162
test_peer_end_frame(freerdp_peer * client)163 static void test_peer_end_frame(freerdp_peer* client)
164 {
165 rdpUpdate* update = client->update;
166 SURFACE_FRAME_MARKER fm = { 0 };
167 testPeerContext* context = (testPeerContext*)client->context;
168 fm.frameAction = SURFACECMD_FRAMEACTION_END;
169 fm.frameId = context->frame_id;
170 update->SurfaceFrameMarker(update->context, &fm);
171 context->frame_id++;
172 }
173
test_peer_draw_background(freerdp_peer * client)174 static BOOL test_peer_draw_background(freerdp_peer* client)
175 {
176 int size;
177 wStream* s;
178 RFX_RECT rect;
179 BYTE* rgb_data;
180 rdpUpdate* update = client->update;
181 SURFACE_BITS_COMMAND cmd = { 0 };
182 testPeerContext* context = (testPeerContext*)client->context;
183 BOOL ret = FALSE;
184
185 if (!client->settings->RemoteFxCodec && !client->settings->NSCodec)
186 return FALSE;
187
188 s = test_peer_stream_init(context);
189 rect.x = 0;
190 rect.y = 0;
191 rect.width = client->settings->DesktopWidth;
192 rect.height = client->settings->DesktopHeight;
193 size = rect.width * rect.height * 3;
194
195 if (!(rgb_data = malloc(size)))
196 {
197 WLog_ERR(TAG, "Problem allocating memory");
198 return FALSE;
199 }
200
201 memset(rgb_data, 0xA0, size);
202
203 if (client->settings->RemoteFxCodec)
204 {
205 WLog_DBG(TAG, "Using RemoteFX codec");
206 if (!rfx_compose_message(context->rfx_context, s, &rect, 1, rgb_data, rect.width,
207 rect.height, rect.width * 3))
208 {
209 goto out;
210 }
211
212 cmd.bmp.codecID = client->settings->RemoteFxCodecId;
213 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
214 }
215 else
216 {
217 WLog_DBG(TAG, "Using NSCodec");
218 nsc_compose_message(context->nsc_context, s, rgb_data, rect.width, rect.height,
219 rect.width * 3);
220 cmd.bmp.codecID = client->settings->NSCodecId;
221 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
222 }
223
224 cmd.destLeft = 0;
225 cmd.destTop = 0;
226 cmd.destRight = rect.width;
227 cmd.destBottom = rect.height;
228 cmd.bmp.bpp = 32;
229 cmd.bmp.flags = 0;
230 cmd.bmp.width = rect.width;
231 cmd.bmp.height = rect.height;
232 cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
233 cmd.bmp.bitmapData = Stream_Buffer(s);
234 test_peer_begin_frame(client);
235 update->SurfaceBits(update->context, &cmd);
236 test_peer_end_frame(client);
237 ret = TRUE;
238 out:
239 free(rgb_data);
240 return ret;
241 }
242
test_peer_load_icon(freerdp_peer * client)243 static BOOL test_peer_load_icon(freerdp_peer* client)
244 {
245 testPeerContext* context = (testPeerContext*)client->context;
246 FILE* fp;
247 int i;
248 char line[50];
249 BYTE* rgb_data = NULL;
250 int c;
251
252 if (!client->settings->RemoteFxCodec && !client->settings->NSCodec)
253 {
254 WLog_ERR(TAG, "Client doesn't support RemoteFX or NSCodec");
255 return FALSE;
256 }
257
258 if ((fp = winpr_fopen("test_icon.ppm", "r")) == NULL)
259 {
260 WLog_ERR(TAG, "Unable to open test icon");
261 return FALSE;
262 }
263
264 /* P3 */
265 fgets(line, sizeof(line), fp);
266 /* Creater comment */
267 fgets(line, sizeof(line), fp);
268 /* width height */
269 fgets(line, sizeof(line), fp);
270
271 if (sscanf(line, "%d %d", &context->icon_width, &context->icon_height) < 2)
272 {
273 WLog_ERR(TAG, "Problem while extracting width/height from the icon file");
274 goto out_fail;
275 }
276
277 /* Max */
278 fgets(line, sizeof(line), fp);
279
280 if (!(rgb_data = calloc(context->icon_height, context->icon_width * 3)))
281 goto out_fail;
282
283 for (i = 0; i < context->icon_width * context->icon_height * 3; i++)
284 {
285 if (!fgets(line, sizeof(line), fp) || (sscanf(line, "%d", &c) != 1))
286 goto out_fail;
287
288 rgb_data[i] = (BYTE)c;
289 }
290
291 /* background with same size, which will be used to erase the icon from old position */
292 if (!(context->bg_data = calloc(context->icon_height, context->icon_width * 3)))
293 goto out_fail;
294
295 memset(context->bg_data, 0xA0, context->icon_width * context->icon_height * 3);
296 context->icon_data = rgb_data;
297 fclose(fp);
298 return TRUE;
299 out_fail:
300 free(rgb_data);
301 context->bg_data = NULL;
302 fclose(fp);
303 return FALSE;
304 }
305
test_peer_draw_icon(freerdp_peer * client,int x,int y)306 static void test_peer_draw_icon(freerdp_peer* client, int x, int y)
307 {
308 wStream* s;
309 RFX_RECT rect;
310 rdpUpdate* update = client->update;
311 SURFACE_BITS_COMMAND cmd = { 0 };
312 testPeerContext* context = (testPeerContext*)client->context;
313
314 if (client->update->dump_rfx)
315 return;
316
317 if (!context)
318 return;
319
320 if (context->icon_width < 1 || !context->activated)
321 return;
322
323 test_peer_begin_frame(client);
324 rect.x = 0;
325 rect.y = 0;
326 rect.width = context->icon_width;
327 rect.height = context->icon_height;
328
329 if (client->settings->RemoteFxCodec)
330 {
331 cmd.bmp.codecID = client->settings->RemoteFxCodecId;
332 cmd.cmdType = CMDTYPE_STREAM_SURFACE_BITS;
333 }
334 else
335 {
336 cmd.bmp.codecID = client->settings->NSCodecId;
337 cmd.cmdType = CMDTYPE_SET_SURFACE_BITS;
338 }
339
340 if (context->icon_x >= 0)
341 {
342 s = test_peer_stream_init(context);
343
344 if (client->settings->RemoteFxCodec)
345 rfx_compose_message(context->rfx_context, s, &rect, 1, context->bg_data, rect.width,
346 rect.height, rect.width * 3);
347 else
348 nsc_compose_message(context->nsc_context, s, context->bg_data, rect.width, rect.height,
349 rect.width * 3);
350
351 cmd.destLeft = context->icon_x;
352 cmd.destTop = context->icon_y;
353 cmd.destRight = context->icon_x + context->icon_width;
354 cmd.destBottom = context->icon_y + context->icon_height;
355 cmd.bmp.bpp = 32;
356 cmd.bmp.flags = 0;
357 cmd.bmp.width = context->icon_width;
358 cmd.bmp.height = context->icon_height;
359 cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
360 cmd.bmp.bitmapData = Stream_Buffer(s);
361 update->SurfaceBits(update->context, &cmd);
362 }
363
364 s = test_peer_stream_init(context);
365
366 if (client->settings->RemoteFxCodec)
367 rfx_compose_message(context->rfx_context, s, &rect, 1, context->icon_data, rect.width,
368 rect.height, rect.width * 3);
369 else
370 nsc_compose_message(context->nsc_context, s, context->icon_data, rect.width, rect.height,
371 rect.width * 3);
372
373 cmd.destLeft = x;
374 cmd.destTop = y;
375 cmd.destRight = x + context->icon_width;
376 cmd.destBottom = y + context->icon_height;
377 cmd.bmp.bpp = 32;
378 cmd.bmp.width = context->icon_width;
379 cmd.bmp.height = context->icon_height;
380 cmd.bmp.bitmapDataLength = Stream_GetPosition(s);
381 cmd.bmp.bitmapData = Stream_Buffer(s);
382 update->SurfaceBits(update->context, &cmd);
383 context->icon_x = x;
384 context->icon_y = y;
385 test_peer_end_frame(client);
386 }
387
test_sleep_tsdiff(UINT32 * old_sec,UINT32 * old_usec,UINT32 new_sec,UINT32 new_usec)388 static BOOL test_sleep_tsdiff(UINT32* old_sec, UINT32* old_usec, UINT32 new_sec, UINT32 new_usec)
389 {
390 INT32 sec, usec;
391
392 if ((*old_sec == 0) && (*old_usec == 0))
393 {
394 *old_sec = new_sec;
395 *old_usec = new_usec;
396 return TRUE;
397 }
398
399 sec = new_sec - *old_sec;
400 usec = new_usec - *old_usec;
401
402 if ((sec < 0) || ((sec == 0) && (usec < 0)))
403 {
404 WLog_ERR(TAG, "Invalid time stamp detected.");
405 return FALSE;
406 }
407
408 *old_sec = new_sec;
409 *old_usec = new_usec;
410
411 while (usec < 0)
412 {
413 usec += 1000000;
414 sec--;
415 }
416
417 if (sec > 0)
418 Sleep(sec * 1000);
419
420 if (usec > 0)
421 USleep(usec);
422
423 return TRUE;
424 }
425
tf_peer_dump_rfx(freerdp_peer * client)426 BOOL tf_peer_dump_rfx(freerdp_peer* client)
427 {
428 wStream* s;
429 UINT32 prev_seconds;
430 UINT32 prev_useconds;
431 rdpUpdate* update;
432 rdpPcap* pcap_rfx;
433 pcap_record record;
434 s = Stream_New(NULL, 512);
435
436 if (!s)
437 return FALSE;
438
439 update = client->update;
440
441 if (!(pcap_rfx = pcap_open(test_pcap_file, FALSE)))
442 return FALSE;
443
444 prev_seconds = prev_useconds = 0;
445
446 while (pcap_has_next_record(pcap_rfx))
447 {
448 if (!pcap_get_next_record_header(pcap_rfx, &record))
449 break;
450
451 if (!Stream_EnsureCapacity(s, record.length))
452 break;
453
454 record.data = Stream_Buffer(s);
455 pcap_get_next_record_content(pcap_rfx, &record);
456 Stream_SetPointer(s, Stream_Buffer(s) + Stream_Capacity(s));
457
458 if (test_dump_rfx_realtime &&
459 test_sleep_tsdiff(&prev_seconds, &prev_useconds, record.header.ts_sec,
460 record.header.ts_usec) == FALSE)
461 break;
462
463 update->SurfaceCommand(update->context, s);
464
465 if (client->CheckFileDescriptor(client) != TRUE)
466 break;
467 }
468
469 Stream_Free(s, TRUE);
470 pcap_close(pcap_rfx);
471 return TRUE;
472 }
473
tf_debug_channel_thread_func(LPVOID arg)474 static DWORD WINAPI tf_debug_channel_thread_func(LPVOID arg)
475 {
476 void* fd;
477 wStream* s;
478 void* buffer;
479 DWORD BytesReturned = 0;
480 ULONG written;
481 testPeerContext* context = (testPeerContext*)arg;
482
483 if (WTSVirtualChannelQuery(context->debug_channel, WTSVirtualFileHandle, &buffer,
484 &BytesReturned) == TRUE)
485 {
486 fd = *((void**)buffer);
487 WTSFreeMemory(buffer);
488
489 if (!(context->event = CreateWaitObjectEvent(NULL, TRUE, FALSE, fd)))
490 return 0;
491 }
492
493 s = Stream_New(NULL, 4096);
494 WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test1", 5, &written);
495
496 while (1)
497 {
498 WaitForSingleObject(context->event, INFINITE);
499
500 if (WaitForSingleObject(context->stopEvent, 0) == WAIT_OBJECT_0)
501 break;
502
503 Stream_SetPosition(s, 0);
504
505 if (WTSVirtualChannelRead(context->debug_channel, 0, (PCHAR)Stream_Buffer(s),
506 Stream_Capacity(s), &BytesReturned) == FALSE)
507 {
508 if (BytesReturned == 0)
509 break;
510
511 Stream_EnsureRemainingCapacity(s, BytesReturned);
512
513 if (WTSVirtualChannelRead(context->debug_channel, 0, (PCHAR)Stream_Buffer(s),
514 Stream_Capacity(s), &BytesReturned) == FALSE)
515 {
516 /* should not happen */
517 break;
518 }
519 }
520
521 Stream_SetPosition(s, BytesReturned);
522 WLog_DBG(TAG, "got %" PRIu32 " bytes", BytesReturned);
523 }
524
525 Stream_Free(s, TRUE);
526 return 0;
527 }
528
tf_peer_post_connect(freerdp_peer * client)529 BOOL tf_peer_post_connect(freerdp_peer* client)
530 {
531 testPeerContext* context = (testPeerContext*)client->context;
532 /**
533 * This callback is called when the entire connection sequence is done, i.e. we've received the
534 * Font List PDU from the client and sent out the Font Map PDU.
535 * The server may start sending graphics output and receiving keyboard/mouse input after this
536 * callback returns.
537 */
538 WLog_DBG(TAG, "Client %s is activated (osMajorType %" PRIu32 " osMinorType %" PRIu32 ")",
539 client->local ? "(local)" : client->hostname, client->settings->OsMajorType,
540 client->settings->OsMinorType);
541
542 if (client->settings->AutoLogonEnabled)
543 {
544 WLog_DBG(TAG, " and wants to login automatically as %s\\%s",
545 client->settings->Domain ? client->settings->Domain : "",
546 client->settings->Username);
547 /* A real server may perform OS login here if NLA is not executed previously. */
548 }
549
550 WLog_DBG(TAG, "");
551 WLog_DBG(TAG, "Client requested desktop: %" PRIu32 "x%" PRIu32 "x%" PRIu32 "",
552 client->settings->DesktopWidth, client->settings->DesktopHeight,
553 client->settings->ColorDepth);
554 #if (SAMPLE_SERVER_USE_CLIENT_RESOLUTION == 1)
555
556 if (!rfx_context_reset(context->rfx_context, client->settings->DesktopWidth,
557 client->settings->DesktopHeight))
558 return FALSE;
559
560 WLog_DBG(TAG, "Using resolution requested by client.");
561 #else
562 client->settings->DesktopWidth = context->rfx_context->width;
563 client->settings->DesktopHeight = context->rfx_context->height;
564 WLog_DBG(TAG, "Resizing client to %" PRIu32 "x%" PRIu32 "", client->settings->DesktopWidth,
565 client->settings->DesktopHeight);
566 client->update->DesktopResize(client->update->context);
567 #endif
568
569 /* A real server should tag the peer as activated here and start sending updates in main loop.
570 */
571 if (!test_peer_load_icon(client))
572 {
573 WLog_DBG(TAG, "Unable to load icon");
574 return FALSE;
575 }
576
577 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpdbg"))
578 {
579 context->debug_channel = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpdbg");
580
581 if (context->debug_channel != NULL)
582 {
583 WLog_DBG(TAG, "Open channel rdpdbg.");
584
585 if (!(context->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
586 {
587 WLog_ERR(TAG, "Failed to create stop event");
588 return FALSE;
589 }
590
591 if (!(context->debug_channel_thread =
592 CreateThread(NULL, 0, tf_debug_channel_thread_func, (void*)context, 0, NULL)))
593 {
594 WLog_ERR(TAG, "Failed to create debug channel thread");
595 CloseHandle(context->stopEvent);
596 context->stopEvent = NULL;
597 return FALSE;
598 }
599 }
600 }
601
602 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "rdpsnd"))
603 {
604 sf_peer_rdpsnd_init(context); /* Audio Output */
605 }
606
607 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, ENCOMSP_SVC_CHANNEL_NAME))
608 {
609 sf_peer_encomsp_init(context); /* Lync Multiparty */
610 }
611
612 /* Dynamic Virtual Channels */
613 sf_peer_audin_init(context); /* Audio Input */
614 /* Return FALSE here would stop the execution of the peer main loop. */
615 return TRUE;
616 }
617
tf_peer_activate(freerdp_peer * client)618 BOOL tf_peer_activate(freerdp_peer* client)
619 {
620 testPeerContext* context = (testPeerContext*)client->context;
621 context->activated = TRUE;
622 // client->settings->CompressionLevel = PACKET_COMPR_TYPE_8K;
623 // client->settings->CompressionLevel = PACKET_COMPR_TYPE_64K;
624 // client->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP6;
625 client->settings->CompressionLevel = PACKET_COMPR_TYPE_RDP61;
626
627 if (test_pcap_file != NULL)
628 {
629 client->update->dump_rfx = TRUE;
630
631 if (!tf_peer_dump_rfx(client))
632 return FALSE;
633 }
634 else
635 test_peer_draw_background(client);
636
637 return TRUE;
638 }
639
tf_peer_synchronize_event(rdpInput * input,UINT32 flags)640 BOOL tf_peer_synchronize_event(rdpInput* input, UINT32 flags)
641 {
642 WINPR_UNUSED(input);
643 WLog_DBG(TAG, "Client sent a synchronize event (flags:0x%" PRIX32 ")", flags);
644 return TRUE;
645 }
646
tf_peer_keyboard_event(rdpInput * input,UINT16 flags,UINT16 code)647 BOOL tf_peer_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
648 {
649 freerdp_peer* client = input->context->peer;
650 rdpUpdate* update = client->update;
651 testPeerContext* context = (testPeerContext*)input->context;
652 WLog_DBG(TAG, "Client sent a keyboard event (flags:0x%04" PRIX16 " code:0x%04" PRIX16 ")",
653 flags, code);
654
655 if ((flags & 0x4000) && code == 0x22) /* 'g' key */
656 {
657 if (client->settings->DesktopWidth != 800)
658 {
659 client->settings->DesktopWidth = 800;
660 client->settings->DesktopHeight = 600;
661 }
662 else
663 {
664 client->settings->DesktopWidth = SAMPLE_SERVER_DEFAULT_WIDTH;
665 client->settings->DesktopHeight = SAMPLE_SERVER_DEFAULT_HEIGHT;
666 }
667
668 if (!rfx_context_reset(context->rfx_context, client->settings->DesktopWidth,
669 client->settings->DesktopHeight))
670 return FALSE;
671
672 update->DesktopResize(update->context);
673 context->activated = FALSE;
674 }
675 else if ((flags & 0x4000) && code == 0x2E) /* 'c' key */
676 {
677 if (context->debug_channel)
678 {
679 ULONG written;
680 WTSVirtualChannelWrite(context->debug_channel, (PCHAR) "test2", 5, &written);
681 }
682 }
683 else if ((flags & 0x4000) && code == 0x2D) /* 'x' key */
684 {
685 client->Close(client);
686 }
687 else if ((flags & 0x4000) && code == 0x13) /* 'r' key */
688 {
689 context->audin_open = !context->audin_open;
690 }
691 else if ((flags & 0x4000) && code == 0x1F) /* 's' key */
692 {
693 }
694
695 return TRUE;
696 }
697
tf_peer_unicode_keyboard_event(rdpInput * input,UINT16 flags,UINT16 code)698 BOOL tf_peer_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code)
699 {
700 WINPR_UNUSED(input);
701 WLog_DBG(TAG,
702 "Client sent a unicode keyboard event (flags:0x%04" PRIX16 " code:0x%04" PRIX16 ")",
703 flags, code);
704 return TRUE;
705 }
706
tf_peer_mouse_event(rdpInput * input,UINT16 flags,UINT16 x,UINT16 y)707 BOOL tf_peer_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
708 {
709 WINPR_UNUSED(flags);
710 // WLog_DBG(TAG, "Client sent a mouse event (flags:0x%04"PRIX16" pos:%"PRIu16",%"PRIu16")",
711 // flags, x, y);
712 test_peer_draw_icon(input->context->peer, x + 10, y);
713 return TRUE;
714 }
715
tf_peer_extended_mouse_event(rdpInput * input,UINT16 flags,UINT16 x,UINT16 y)716 BOOL tf_peer_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT16 y)
717 {
718 WINPR_UNUSED(flags);
719 // WLog_DBG(TAG, "Client sent an extended mouse event (flags:0x%04"PRIX16"
720 // pos:%"PRIu16",%"PRIu16")", flags, x, y);
721 test_peer_draw_icon(input->context->peer, x + 10, y);
722 return TRUE;
723 }
724
tf_peer_refresh_rect(rdpContext * context,BYTE count,const RECTANGLE_16 * areas)725 static BOOL tf_peer_refresh_rect(rdpContext* context, BYTE count, const RECTANGLE_16* areas)
726 {
727 BYTE i;
728 WINPR_UNUSED(context);
729 WLog_DBG(TAG, "Client requested to refresh:");
730
731 for (i = 0; i < count; i++)
732 {
733 WLog_DBG(TAG, " (%" PRIu16 ", %" PRIu16 ") (%" PRIu16 ", %" PRIu16 ")", areas[i].left,
734 areas[i].top, areas[i].right, areas[i].bottom);
735 }
736
737 return TRUE;
738 }
739
tf_peer_suppress_output(rdpContext * context,BYTE allow,const RECTANGLE_16 * area)740 static BOOL tf_peer_suppress_output(rdpContext* context, BYTE allow, const RECTANGLE_16* area)
741 {
742 WINPR_UNUSED(context);
743
744 if (allow > 0)
745 {
746 WLog_DBG(TAG,
747 "Client restore output (%" PRIu16 ", %" PRIu16 ") (%" PRIu16 ", %" PRIu16 ").",
748 area->left, area->top, area->right, area->bottom);
749 }
750 else
751 {
752 WLog_DBG(TAG, "Client minimized and suppress output.");
753 }
754
755 return TRUE;
756 }
757
test_peer_mainloop(LPVOID arg)758 static DWORD WINAPI test_peer_mainloop(LPVOID arg)
759 {
760 DWORD error = CHANNEL_RC_OK;
761 HANDLE handles[32];
762 DWORD count;
763 DWORD status;
764 testPeerContext* context;
765 freerdp_peer* client = (freerdp_peer*)arg;
766
767 if (!test_peer_init(client))
768 {
769 freerdp_peer_free(client);
770 return 0;
771 }
772
773 /* Initialize the real server settings here */
774 client->settings->CertificateFile = _strdup("server.crt");
775 client->settings->PrivateKeyFile = _strdup("server.key");
776 client->settings->RdpKeyFile = _strdup("server.key");
777
778 if (!client->settings->CertificateFile || !client->settings->PrivateKeyFile ||
779 !client->settings->RdpKeyFile)
780 {
781 WLog_ERR(TAG, "Memory allocation failed (strdup)");
782 freerdp_peer_free(client);
783 return 0;
784 }
785
786 client->settings->RdpSecurity = TRUE;
787 client->settings->TlsSecurity = TRUE;
788 client->settings->NlaSecurity = FALSE;
789 client->settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
790 /* client->settings->EncryptionLevel = ENCRYPTION_LEVEL_HIGH; */
791 /* client->settings->EncryptionLevel = ENCRYPTION_LEVEL_LOW; */
792 /* client->settings->EncryptionLevel = ENCRYPTION_LEVEL_FIPS; */
793 client->settings->RemoteFxCodec = TRUE;
794 client->settings->NSCodec = TRUE;
795 client->settings->ColorDepth = 32;
796 client->settings->SuppressOutput = TRUE;
797 client->settings->RefreshRect = TRUE;
798 client->PostConnect = tf_peer_post_connect;
799 client->Activate = tf_peer_activate;
800 client->input->SynchronizeEvent = tf_peer_synchronize_event;
801 client->input->KeyboardEvent = tf_peer_keyboard_event;
802 client->input->UnicodeKeyboardEvent = tf_peer_unicode_keyboard_event;
803 client->input->MouseEvent = tf_peer_mouse_event;
804 client->input->ExtendedMouseEvent = tf_peer_extended_mouse_event;
805 client->update->RefreshRect = tf_peer_refresh_rect;
806 client->update->SuppressOutput = tf_peer_suppress_output;
807 client->settings->MultifragMaxRequestSize = 0xFFFFFF; /* FIXME */
808 client->Initialize(client);
809 context = (testPeerContext*)client->context;
810 WLog_INFO(TAG, "We've got a client %s", client->local ? "(local)" : client->hostname);
811
812 while (error == CHANNEL_RC_OK)
813 {
814 count = 0;
815 {
816 DWORD tmp = client->GetEventHandles(client, &handles[count], 32 - count);
817
818 if (tmp == 0)
819 {
820 WLog_ERR(TAG, "Failed to get FreeRDP transport event handles");
821 break;
822 }
823
824 count += tmp;
825 }
826 handles[count++] = WTSVirtualChannelManagerGetEventHandle(context->vcm);
827 status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
828
829 if (status == WAIT_FAILED)
830 {
831 WLog_ERR(TAG, "WaitForMultipleObjects failed (errno: %d)", errno);
832 break;
833 }
834
835 if (client->CheckFileDescriptor(client) != TRUE)
836 break;
837
838 if (WTSVirtualChannelManagerCheckFileDescriptor(context->vcm) != TRUE)
839 break;
840
841 /* Handle dynamic virtual channel intializations */
842 if (WTSVirtualChannelManagerIsChannelJoined(context->vcm, "drdynvc"))
843 {
844 switch (WTSVirtualChannelManagerGetDrdynvcState(context->vcm))
845 {
846 case DRDYNVC_STATE_NONE:
847 break;
848
849 case DRDYNVC_STATE_INITIALIZED:
850 break;
851
852 case DRDYNVC_STATE_READY:
853
854 /* Here is the correct state to start dynamic virtual channels */
855 if (sf_peer_audin_running(context) != context->audin_open)
856 {
857 if (!sf_peer_audin_running(context))
858 sf_peer_audin_start(context);
859 else
860 sf_peer_audin_stop(context);
861 }
862
863 break;
864
865 case DRDYNVC_STATE_FAILED:
866 default:
867 break;
868 }
869 }
870 }
871
872 WLog_INFO(TAG, "Client %s disconnected.", client->local ? "(local)" : client->hostname);
873 client->Disconnect(client);
874 freerdp_peer_context_free(client);
875 freerdp_peer_free(client);
876 return error;
877 }
878
test_peer_accepted(freerdp_listener * instance,freerdp_peer * client)879 static BOOL test_peer_accepted(freerdp_listener* instance, freerdp_peer* client)
880 {
881 HANDLE hThread;
882 WINPR_UNUSED(instance);
883
884 if (!(hThread = CreateThread(NULL, 0, test_peer_mainloop, (void*)client, 0, NULL)))
885 return FALSE;
886
887 CloseHandle(hThread);
888 return TRUE;
889 }
890
test_server_mainloop(freerdp_listener * instance)891 static void test_server_mainloop(freerdp_listener* instance)
892 {
893 HANDLE handles[32];
894 DWORD count;
895 DWORD status;
896
897 while (1)
898 {
899 count = instance->GetEventHandles(instance, handles, 32);
900
901 if (0 == count)
902 {
903 WLog_ERR(TAG, "Failed to get FreeRDP event handles");
904 break;
905 }
906
907 status = WaitForMultipleObjects(count, handles, FALSE, INFINITE);
908
909 if (WAIT_FAILED == status)
910 {
911 WLog_ERR(TAG, "select failed");
912 break;
913 }
914
915 if (instance->CheckFileDescriptor(instance) != TRUE)
916 {
917 WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
918 break;
919 }
920 }
921
922 instance->Close(instance);
923 }
924
main(int argc,char * argv[])925 int main(int argc, char* argv[])
926 {
927 const char spcap[] = "--";
928 const char sfast[] = "--fast";
929 const char sport[] = "--port=";
930 const char slocal_only[] = "--local_only";
931 WSADATA wsaData;
932 freerdp_listener* instance;
933 char* file;
934 char name[MAX_PATH];
935 long port = 3389, i;
936 BOOL localOnly = FALSE;
937 errno = 0;
938
939 for (i = 1; i < argc; i++)
940 {
941 char* arg = argv[i];
942
943 if (strncmp(arg, sfast, sizeof(sfast)) == 0)
944 test_dump_rfx_realtime = FALSE;
945 else if (strncmp(arg, sport, sizeof(sport) - 1) == 0)
946 {
947 StrSep(&arg, "=");
948
949 if (!arg)
950 return -1;
951
952 port = strtol(arg, NULL, 10);
953
954 if ((port < 1) || (port > 0xFFFF) || (errno != 0))
955 return -1;
956 }
957 else if (strncmp(arg, slocal_only, sizeof(slocal_only)) == 0)
958 localOnly = TRUE;
959 else if (strncmp(arg, spcap, sizeof(spcap)) == 0)
960 test_pcap_file = arg;
961 }
962
963 WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
964 winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
965 instance = freerdp_listener_new();
966
967 if (!instance)
968 return -1;
969
970 instance->PeerAccepted = test_peer_accepted;
971
972 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
973 {
974 freerdp_listener_free(instance);
975 return -1;
976 }
977
978 /* Open the server socket and start listening. */
979 sprintf_s(name, sizeof(name), "tfreerdp-server.%ld", port);
980 file = GetKnownSubPath(KNOWN_PATH_TEMP, name);
981
982 if (!file)
983 {
984 freerdp_listener_free(instance);
985 WSACleanup();
986 return -1;
987 }
988
989 if ((localOnly || instance->Open(instance, NULL, port)) && instance->OpenLocal(instance, file))
990 {
991 /* Entering the server main loop. In a real server the listener can be run in its own
992 * thread. */
993 test_server_mainloop(instance);
994 }
995
996 free(file);
997 freerdp_listener_free(instance);
998 WSACleanup();
999 return 0;
1000 }
1001