FreeRDP
Loading...
Searching...
No Matches
gfxredir_main.c
1
20#include <freerdp/config.h>
21
22#include "gfxredir_main.h"
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <winpr/crt.h>
28#include <winpr/assert.h>
29#include <winpr/synch.h>
30#include <winpr/thread.h>
31#include <winpr/stream.h>
32#include <winpr/sysinfo.h>
33#include <freerdp/channels/wtsvc.h>
34#include <freerdp/channels/log.h>
35
36#include <freerdp/server/gfxredir.h>
37#include <gfxredir_common.h>
38
39#define TAG CHANNELS_TAG("gfxredir.server")
40
46static UINT gfxredir_recv_legacy_caps_pdu(wStream* s, GfxRedirServerContext* context)
47{
48 UINT32 error = CHANNEL_RC_OK;
49 GFXREDIR_LEGACY_CAPS_PDU pdu = WINPR_C_ARRAY_INIT;
50
51 WINPR_ASSERT(context);
52
53 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
54 return ERROR_INVALID_DATA;
55
56 Stream_Read_UINT16(s, pdu.version); /* version (2 bytes) */
57
58 if (context)
59 IFCALLRET(context->GraphicsRedirectionLegacyCaps, error, context, &pdu);
60
61 return error;
62}
63
69static UINT gfxredir_recv_caps_advertise_pdu(wStream* s, UINT32 length,
70 GfxRedirServerContext* context)
71{
72 UINT32 error = CHANNEL_RC_OK;
73 GFXREDIR_CAPS_ADVERTISE_PDU pdu = WINPR_C_ARRAY_INIT;
74
75 WINPR_ASSERT(context);
76
77 if (!Stream_CheckAndLogRequiredLength(TAG, s, length))
78 return ERROR_INVALID_DATA;
79
80 pdu.length = length;
81 Stream_GetPointer(s, pdu.caps);
82 Stream_Seek(s, length);
83
84 if (!context->GraphicsRedirectionCapsAdvertise)
85 {
86 WLog_ERR(TAG, "server does not support CapsAdvertise PDU!");
87 return ERROR_NOT_SUPPORTED;
88 }
89 else if (context)
90 {
91 IFCALLRET(context->GraphicsRedirectionCapsAdvertise, error, context, &pdu);
92 }
93
94 return error;
95}
96
102static UINT gfxredir_recv_present_buffer_ack_pdu(wStream* s, GfxRedirServerContext* context)
103{
104 UINT32 error = CHANNEL_RC_OK;
105 GFXREDIR_PRESENT_BUFFER_ACK_PDU pdu = WINPR_C_ARRAY_INIT;
106
107 WINPR_ASSERT(context);
108
109 if (!Stream_CheckAndLogRequiredLength(TAG, s, 16))
110 return ERROR_INVALID_DATA;
111
112 Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */
113 Stream_Read_UINT64(s, pdu.presentId); /* presentId (8 bytes) */
114
115 if (context)
116 {
117 IFCALLRET(context->PresentBufferAck, error, context, &pdu);
118 }
119
120 return error;
121}
122
128static UINT gfxredir_server_receive_pdu(GfxRedirServerContext* context, wStream* s)
129{
130 UINT error = CHANNEL_RC_OK;
131 GFXREDIR_HEADER header = WINPR_C_ARRAY_INIT;
132
133 WINPR_ASSERT(context);
134
135 const size_t beg = Stream_GetPosition(s);
136
137 if ((error = gfxredir_read_header(s, &header)))
138 {
139 WLog_ERR(TAG, "gfxredir_read_header failed with error %" PRIu32 "!", error);
140 return error;
141 }
142
143 switch (header.cmdId)
144 {
145 case GFXREDIR_CMDID_LEGACY_CAPS:
146 if ((error = gfxredir_recv_legacy_caps_pdu(s, context)))
147 WLog_ERR(TAG,
148 "gfxredir_recv_legacy_caps_pdu "
149 "failed with error %" PRIu32 "!",
150 error);
151
152 break;
153
154 case GFXREDIR_CMDID_CAPS_ADVERTISE:
155 if ((error = gfxredir_recv_caps_advertise_pdu(s, header.length - 8, context)))
156 WLog_ERR(TAG,
157 "gfxredir_recv_caps_advertise "
158 "failed with error %" PRIu32 "!",
159 error);
160 break;
161
162 case GFXREDIR_CMDID_PRESENT_BUFFER_ACK:
163 if ((error = gfxredir_recv_present_buffer_ack_pdu(s, context)))
164 WLog_ERR(TAG,
165 "gfxredir_recv_present_buffer_ask_pdu "
166 "failed with error %" PRIu32 "!",
167 error);
168 break;
169
170 default:
171 error = CHANNEL_RC_BAD_PROC;
172 WLog_WARN(TAG, "Received unknown PDU type: %" PRIu32 "", header.cmdId);
173 break;
174 }
175
176 const size_t end = Stream_GetPosition(s);
177
178 if (end != (beg + header.length))
179 {
180 WLog_ERR(TAG, "Unexpected GFXREDIR pdu end: Actual: %" PRIuz ", Expected: %" PRIuz "", end,
181 (beg + header.length));
182 if (!Stream_SetPosition(s, (beg + header.length)))
183 return ERROR_INVALID_DATA;
184 }
185
186 return error;
187}
188
194static UINT gfxredir_server_handle_messages(GfxRedirServerContext* context)
195{
196 UINT ret = CHANNEL_RC_OK;
197
198 WINPR_ASSERT(context);
199
200 GfxRedirServerPrivate* priv = context->priv;
201 WINPR_ASSERT(priv);
202
203 wStream* s = priv->input_stream;
204
205 /* Check whether the dynamic channel is ready */
206 if (!priv->isReady)
207 {
208 void* buffer = nullptr;
209 DWORD BytesReturned = 0;
210 if (WTSVirtualChannelQuery(priv->gfxredir_channel, WTSVirtualChannelReady, &buffer,
211 &BytesReturned) == FALSE)
212 {
213 if (GetLastError() == ERROR_NO_DATA)
214 return ERROR_NO_DATA;
215
216 WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
217 return ERROR_INTERNAL_ERROR;
218 }
219
220 priv->isReady = *((BOOL*)buffer);
221 WTSFreeMemory(buffer);
222 }
223
224 /* Consume channel event only after the dynamic channel is ready */
225 if (priv->isReady)
226 {
227 Stream_ResetPosition(s);
228
229 DWORD BytesReturned = 0;
230 if (!WTSVirtualChannelRead(priv->gfxredir_channel, 0, nullptr, 0, &BytesReturned))
231 {
232 if (GetLastError() == ERROR_NO_DATA)
233 return ERROR_NO_DATA;
234
235 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
236 return ERROR_INTERNAL_ERROR;
237 }
238
239 if (BytesReturned < 1)
240 return CHANNEL_RC_OK;
241
242 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
243 {
244 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
245 return CHANNEL_RC_NO_MEMORY;
246 }
247
248 const ULONG cap = WINPR_ASSERTING_INT_CAST(ULONG, Stream_Capacity(s));
249 if (WTSVirtualChannelRead(priv->gfxredir_channel, 0, (PCHAR)Stream_Buffer(s), cap,
250 &BytesReturned) == FALSE)
251 {
252 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
253 return ERROR_INTERNAL_ERROR;
254 }
255
256 if (!Stream_SetLength(s, BytesReturned))
257 return ERROR_INTERNAL_ERROR;
258
259 Stream_ResetPosition(s);
260
261 while (Stream_GetPosition(s) < Stream_Length(s))
262 {
263 if ((ret = gfxredir_server_receive_pdu(context, s)))
264 {
265 WLog_ERR(TAG,
266 "gfxredir_server_receive_pdu "
267 "failed with error %" PRIu32 "!",
268 ret);
269 return ret;
270 }
271 }
272 }
273
274 return ret;
275}
276
282static DWORD WINAPI gfxredir_server_thread_func(LPVOID arg)
283{
284 GfxRedirServerContext* context = (GfxRedirServerContext*)arg;
285 WINPR_ASSERT(context);
286
287 GfxRedirServerPrivate* priv = context->priv;
288 WINPR_ASSERT(priv);
289
290 HANDLE events[8] = WINPR_C_ARRAY_INIT;
291 UINT error = CHANNEL_RC_OK;
292 DWORD nCount = 0;
293 events[nCount++] = priv->stopEvent;
294 events[nCount++] = priv->channelEvent;
295
296 while (TRUE)
297 {
298 const DWORD status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
299
300 if (status == WAIT_FAILED)
301 {
302 error = GetLastError();
303 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
304 break;
305 }
306
307 /* Stop Event */
308 if (status == WAIT_OBJECT_0)
309 break;
310
311 if ((error = gfxredir_server_handle_messages(context)))
312 {
313 WLog_ERR(TAG, "gfxredir_server_handle_messages failed with error %" PRIu32 "", error);
314 break;
315 }
316 }
317
318 ExitThread(error);
319 return error;
320}
321
333static wStream* gfxredir_server_single_packet_new(UINT32 cmdId, size_t length)
334{
335 GFXREDIR_HEADER header = WINPR_C_ARRAY_INIT;
336 wStream* s = Stream_New(nullptr, GFXREDIR_HEADER_SIZE + length);
337
338 if (!s)
339 {
340 WLog_ERR(TAG, "Stream_New failed!");
341 goto error;
342 }
343
344 header.cmdId = cmdId;
345 header.length = WINPR_ASSERTING_INT_CAST(UINT32, GFXREDIR_HEADER_SIZE + length);
346
347 const UINT error = gfxredir_write_header(s, &header);
348 if (error)
349 {
350 WLog_ERR(TAG, "Failed to write header with error %" PRIu32 "!", error);
351 goto error;
352 }
353
354 return s;
355error:
356 Stream_Free(s, TRUE);
357 return nullptr;
358}
359
365static UINT gfxredir_server_packet_send(GfxRedirServerContext* context, wStream* s)
366{
367 UINT ret = ERROR_INTERNAL_ERROR;
368 ULONG written = 0;
369
370 WINPR_ASSERT(context);
371
372 const ULONG cap = WINPR_ASSERTING_INT_CAST(ULONG, Stream_GetPosition(s));
373 if (!WTSVirtualChannelWrite(context->priv->gfxredir_channel, (PCHAR)Stream_Buffer(s), cap,
374 &written))
375 {
376 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
377 ret = ERROR_INTERNAL_ERROR;
378 goto out;
379 }
380
381 if (written < Stream_GetPosition(s))
382 {
383 WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
384 Stream_GetPosition(s));
385 }
386
387 ret = CHANNEL_RC_OK;
388out:
389 Stream_Free(s, TRUE);
390 return ret;
391}
392
398static UINT gfxredir_send_error(GfxRedirServerContext* context, const GFXREDIR_ERROR_PDU* error)
399{
400 WINPR_ASSERT(context);
401 WINPR_ASSERT(error);
402
403 wStream* s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_ERROR, 4);
404
405 if (!s)
406 {
407 WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!");
408 return CHANNEL_RC_NO_MEMORY;
409 }
410
411 Stream_Write_UINT32(s, error->errorCode);
412 return gfxredir_server_packet_send(context, s);
413}
414
420static UINT gfxredir_send_caps_confirm(GfxRedirServerContext* context,
421 const GFXREDIR_CAPS_CONFIRM_PDU* graphicsCapsConfirm)
422{
423 WINPR_ASSERT(context);
424 WINPR_ASSERT(graphicsCapsConfirm);
425
426 if (graphicsCapsConfirm->length < GFXREDIR_CAPS_HEADER_SIZE)
427 {
428 WLog_ERR(TAG, "length must be greater than header size, failed!");
429 return ERROR_INVALID_DATA;
430 }
431
432 wStream* s =
433 gfxredir_server_single_packet_new(GFXREDIR_CMDID_CAPS_CONFIRM, graphicsCapsConfirm->length);
434
435 if (!s)
436 {
437 WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!");
438 return CHANNEL_RC_NO_MEMORY;
439 }
440
441 Stream_Write_UINT32(s, GFXREDIR_CAPS_SIGNATURE);
442 Stream_Write_UINT32(s, graphicsCapsConfirm->version);
443 Stream_Write_UINT32(s, graphicsCapsConfirm->length);
444 if (graphicsCapsConfirm->length > GFXREDIR_CAPS_HEADER_SIZE)
445 Stream_Write(s, graphicsCapsConfirm->capsData,
446 graphicsCapsConfirm->length - GFXREDIR_CAPS_HEADER_SIZE);
447 const UINT ret = gfxredir_server_packet_send(context, s);
448 if (ret == CHANNEL_RC_OK)
449 context->confirmedCapsVersion = graphicsCapsConfirm->version;
450 return ret;
451}
452
458static UINT gfxredir_send_open_pool(GfxRedirServerContext* context,
459 const GFXREDIR_OPEN_POOL_PDU* openPool)
460{
461 WINPR_ASSERT(context);
462 WINPR_ASSERT(openPool);
463
464 if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0)
465 {
466 WLog_ERR(TAG, "open_pool is called with invalid version!");
467 return ERROR_INTERNAL_ERROR;
468 }
469
470 if (openPool->sectionNameLength == 0 || openPool->sectionName == nullptr)
471 {
472 WLog_ERR(TAG, "section name must be provided!");
473 return ERROR_INVALID_DATA;
474 }
475
476 /* make sure null-terminate */
477 if (openPool->sectionName[openPool->sectionNameLength - 1] != 0)
478 {
479 WLog_ERR(TAG, "section name must be terminated with nullptr!");
480 return ERROR_INVALID_DATA;
481 }
482
483 wStream* s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_OPEN_POOL,
484 20 + (openPool->sectionNameLength * 2));
485
486 if (!s)
487 {
488 WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!");
489 return CHANNEL_RC_NO_MEMORY;
490 }
491
492 Stream_Write_UINT64(s, openPool->poolId);
493 Stream_Write_UINT64(s, openPool->poolSize);
494 Stream_Write_UINT32(s, openPool->sectionNameLength);
495 Stream_Write(s, openPool->sectionName, (2ULL * openPool->sectionNameLength));
496 return gfxredir_server_packet_send(context, s);
497}
498
504static UINT gfxredir_send_close_pool(GfxRedirServerContext* context,
505 const GFXREDIR_CLOSE_POOL_PDU* closePool)
506{
507 WINPR_ASSERT(context);
508 WINPR_ASSERT(closePool);
509
510 if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0)
511 {
512 WLog_ERR(TAG, "close_pool is called with invalid version!");
513 return ERROR_INTERNAL_ERROR;
514 }
515
516 wStream* s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_CLOSE_POOL, 8);
517
518 if (!s)
519 {
520 WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!");
521 return CHANNEL_RC_NO_MEMORY;
522 }
523
524 Stream_Write_UINT64(s, closePool->poolId);
525 return gfxredir_server_packet_send(context, s);
526}
527
533static UINT gfxredir_send_create_buffer(GfxRedirServerContext* context,
534 const GFXREDIR_CREATE_BUFFER_PDU* createBuffer)
535{
536 WINPR_ASSERT(context);
537 WINPR_ASSERT(createBuffer);
538
539 if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0)
540 {
541 WLog_ERR(TAG, "create_buffer is called with invalid version!");
542 return ERROR_INTERNAL_ERROR;
543 }
544
545 wStream* s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_CREATE_BUFFER, 40);
546
547 if (!s)
548 {
549 WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!");
550 return CHANNEL_RC_NO_MEMORY;
551 }
552
553 Stream_Write_UINT64(s, createBuffer->poolId);
554 Stream_Write_UINT64(s, createBuffer->bufferId);
555 Stream_Write_UINT64(s, createBuffer->offset);
556 Stream_Write_UINT32(s, createBuffer->stride);
557 Stream_Write_UINT32(s, createBuffer->width);
558 Stream_Write_UINT32(s, createBuffer->height);
559 Stream_Write_UINT32(s, createBuffer->format);
560 return gfxredir_server_packet_send(context, s);
561}
562
568static UINT gfxredir_send_destroy_buffer(GfxRedirServerContext* context,
569 const GFXREDIR_DESTROY_BUFFER_PDU* destroyBuffer)
570{
571 WINPR_ASSERT(context);
572 WINPR_ASSERT(destroyBuffer);
573
574 if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0)
575 {
576 WLog_ERR(TAG, "destroy_buffer is called with invalid version!");
577 return ERROR_INTERNAL_ERROR;
578 }
579
580 wStream* s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_DESTROY_BUFFER, 8);
581
582 if (!s)
583 {
584 WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!");
585 return CHANNEL_RC_NO_MEMORY;
586 }
587
588 Stream_Write_UINT64(s, destroyBuffer->bufferId);
589 return gfxredir_server_packet_send(context, s);
590}
591
597static UINT gfxredir_send_present_buffer(GfxRedirServerContext* context,
598 const GFXREDIR_PRESENT_BUFFER_PDU* presentBuffer)
599{
600 RECTANGLE_32 dummyRect = { 0, 0, 0, 0 };
601
602 WINPR_ASSERT(context);
603 WINPR_ASSERT(presentBuffer);
604
605 if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0)
606 {
607 WLog_ERR(TAG, "present_buffer is called with invalid version!");
608 return ERROR_INTERNAL_ERROR;
609 }
610
611 if (presentBuffer->numOpaqueRects > GFXREDIR_MAX_OPAQUE_RECTS)
612 {
613 WLog_ERR(TAG, "numOpaqueRects is larger than its limit!");
614 return ERROR_INVALID_DATA;
615 }
616
617 const size_t length =
618 64ULL + ((presentBuffer->numOpaqueRects ? presentBuffer->numOpaqueRects : 1) *
619 sizeof(RECTANGLE_32));
620
621 wStream* s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_PRESENT_BUFFER, length);
622
623 if (!s)
624 {
625 WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!");
626 return CHANNEL_RC_NO_MEMORY;
627 }
628
629 Stream_Write_UINT64(s, presentBuffer->timestamp);
630 Stream_Write_UINT64(s, presentBuffer->presentId);
631 Stream_Write_UINT64(s, presentBuffer->windowId);
632 Stream_Write_UINT64(s, presentBuffer->bufferId);
633 Stream_Write_UINT32(s, presentBuffer->orientation);
634 Stream_Write_UINT32(s, presentBuffer->targetWidth);
635 Stream_Write_UINT32(s, presentBuffer->targetHeight);
636 Stream_Write_UINT32(s, presentBuffer->dirtyRect.left);
637 Stream_Write_UINT32(s, presentBuffer->dirtyRect.top);
638 Stream_Write_UINT32(s, presentBuffer->dirtyRect.width);
639 Stream_Write_UINT32(s, presentBuffer->dirtyRect.height);
640 Stream_Write_UINT32(s, presentBuffer->numOpaqueRects);
641 if (presentBuffer->numOpaqueRects)
642 Stream_Write(s, presentBuffer->opaqueRects,
643 (presentBuffer->numOpaqueRects * sizeof(RECTANGLE_32)));
644 else
645 Stream_Write(s, &dummyRect, sizeof(RECTANGLE_32));
646 return gfxredir_server_packet_send(context, s);
647}
648
654static UINT gfxredir_server_open(GfxRedirServerContext* context)
655{
656 UINT rc = ERROR_INTERNAL_ERROR;
657 WINPR_ASSERT(context);
658
659 GfxRedirServerPrivate* priv = context->priv;
660 WINPR_ASSERT(priv);
661
662 DWORD BytesReturned = 0;
663 PULONG pSessionId = nullptr;
664 void* buffer = nullptr;
665 priv->SessionId = WTS_CURRENT_SESSION;
666
667 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
668 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
669 {
670 WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
671 rc = ERROR_INTERNAL_ERROR;
672 goto out_close;
673 }
674
675 priv->SessionId = (DWORD)*pSessionId;
676 WTSFreeMemory(pSessionId);
677 priv->gfxredir_channel = WTSVirtualChannelOpenEx(priv->SessionId, GFXREDIR_DVC_CHANNEL_NAME,
678 WTS_CHANNEL_OPTION_DYNAMIC);
679
680 if (!priv->gfxredir_channel)
681 {
682 WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!");
683 rc = GetLastError();
684 goto out_close;
685 }
686
687 /* Query for channel event handle */
688 if (!WTSVirtualChannelQuery(priv->gfxredir_channel, WTSVirtualEventHandle, &buffer,
689 &BytesReturned) ||
690 (BytesReturned != sizeof(HANDLE)))
691 {
692 WLog_ERR(TAG,
693 "WTSVirtualChannelQuery failed "
694 "or invalid returned size(%" PRIu32 ")",
695 BytesReturned);
696
697 if (buffer)
698 WTSFreeMemory(buffer);
699
700 rc = ERROR_INTERNAL_ERROR;
701 goto out_close;
702 }
703
704 priv->channelEvent = *(HANDLE*)buffer;
705 WTSFreeMemory(buffer);
706
707 if (priv->thread == nullptr)
708 {
709 if (!(priv->stopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
710 {
711 WLog_ERR(TAG, "CreateEvent failed!");
712 goto out_close;
713 }
714
715 if (!(priv->thread = CreateThread(nullptr, 0, gfxredir_server_thread_func, (void*)context,
716 0, nullptr)))
717 {
718 WLog_ERR(TAG, "CreateEvent failed!");
719 (void)CloseHandle(priv->stopEvent);
720 priv->stopEvent = nullptr;
721 goto out_close;
722 }
723 }
724
725 return CHANNEL_RC_OK;
726out_close:
727 WTSVirtualChannelClose(priv->gfxredir_channel);
728 priv->gfxredir_channel = nullptr;
729 priv->channelEvent = nullptr;
730 return rc;
731}
732
738static UINT gfxredir_server_close(GfxRedirServerContext* context)
739{
740 UINT error = CHANNEL_RC_OK;
741 WINPR_ASSERT(context);
742
743 GfxRedirServerPrivate* priv = context->priv;
744 WINPR_ASSERT(priv);
745
746 if (priv->thread)
747 {
748 (void)SetEvent(priv->stopEvent);
749
750 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
751 {
752 error = GetLastError();
753 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
754 return error;
755 }
756
757 (void)CloseHandle(priv->thread);
758 (void)CloseHandle(priv->stopEvent);
759 priv->thread = nullptr;
760 priv->stopEvent = nullptr;
761 }
762
763 if (priv->gfxredir_channel)
764 {
765 WTSVirtualChannelClose(priv->gfxredir_channel);
766 priv->gfxredir_channel = nullptr;
767 }
768
769 return error;
770}
771
772GfxRedirServerContext* gfxredir_server_context_new(HANDLE vcm)
773{
774 GfxRedirServerContext* context =
775 (GfxRedirServerContext*)calloc(1, sizeof(GfxRedirServerContext));
776
777 if (!context)
778 {
779 WLog_ERR(TAG, "gfxredir_server_context_new(): calloc GfxRedirServerContext failed!");
780 return nullptr;
781 }
782
783 GfxRedirServerPrivate* priv = context->priv =
784 (GfxRedirServerPrivate*)calloc(1, sizeof(GfxRedirServerPrivate));
785
786 if (!context->priv)
787 {
788 WLog_ERR(TAG, "gfxredir_server_context_new(): calloc GfxRedirServerPrivate failed!");
789 goto fail;
790 }
791
792 priv->input_stream = Stream_New(nullptr, 4);
793
794 if (!priv->input_stream)
795 {
796 WLog_ERR(TAG, "Stream_New failed!");
797 goto fail;
798 }
799
800 context->vcm = vcm;
801 context->Open = gfxredir_server_open;
802 context->Close = gfxredir_server_close;
803 context->Error = gfxredir_send_error;
804 context->GraphicsRedirectionCapsConfirm = gfxredir_send_caps_confirm;
805 context->OpenPool = gfxredir_send_open_pool;
806 context->ClosePool = gfxredir_send_close_pool;
807 context->CreateBuffer = gfxredir_send_create_buffer;
808 context->DestroyBuffer = gfxredir_send_destroy_buffer;
809 context->PresentBuffer = gfxredir_send_present_buffer;
810 context->confirmedCapsVersion = GFXREDIR_CAPS_VERSION1;
811 priv->isReady = FALSE;
812 return context;
813fail:
814 gfxredir_server_context_free(context);
815 return nullptr;
816}
817
818void gfxredir_server_context_free(GfxRedirServerContext* context)
819{
820 if (!context)
821 return;
822
823 gfxredir_server_close(context);
824
825 if (context->priv)
826 {
827 Stream_Free(context->priv->input_stream, TRUE);
828 free(context->priv);
829 }
830
831 free(context);
832}