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