FreeRDP
Loading...
Searching...
No Matches
server/rdpgfx_main.c
1
20#include <freerdp/config.h>
21
22#include <winpr/assert.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <winpr/cast.h>
28#include <winpr/crt.h>
29#include <winpr/synch.h>
30#include <winpr/thread.h>
31#include <winpr/stream.h>
32
33#include <freerdp/freerdp.h>
34#include <freerdp/codec/color.h>
35
36#include <freerdp/channels/wtsvc.h>
37#include <freerdp/channels/log.h>
38
39#include "rdpgfx_common.h"
40#include "rdpgfx_main.h"
41
42#define TAG CHANNELS_TAG("rdpgfx.server")
43
44static BOOL rdpgfx_server_close(RdpgfxServerContext* context);
45
46#define checkCapsAreExchanged(context) \
47 checkCapsAreExchangedInt(context, __FILE__, __func__, __LINE__)
48WINPR_ATTR_NODISCARD static BOOL checkCapsAreExchangedInt(RdpgfxServerContext* context,
49 const char* file, const char* fkt,
50 size_t line)
51{
52 WINPR_ASSERT(context);
53 WINPR_ASSERT(context->priv);
54
55 const DWORD level = WLOG_TRACE;
56 if (WLog_IsLevelActive(context->priv->log, level))
57 {
58 WLog_PrintTextMessage(context->priv->log, level, line, file, fkt,
59 "activeCapSet{Version=0x%08" PRIx32 ", flags=0x%08" PRIx32 "}",
60 context->priv->activeCapSet.version,
61 context->priv->activeCapSet.flags);
62 }
63 return context->priv->activeCapSet.version > 0;
64}
65
75WINPR_ATTR_NODISCARD static inline size_t rdpgfx_pdu_length(size_t dataLen)
76{
77 return RDPGFX_HEADER_SIZE + dataLen;
78}
79
80WINPR_ATTR_NODISCARD static inline UINT rdpgfx_server_packet_init_header(wStream* s, UINT16 cmdId,
81 size_t pduLength)
82{
83 const RDPGFX_HEADER header = { .flags = 0,
84 .cmdId = cmdId,
85 .pduLength = WINPR_ASSERTING_INT_CAST(UINT32, pduLength) };
86 /* Write header. Note that actual length might be changed
87 * after the entire packet has been constructed. */
88 return rdpgfx_write_header(s, &header);
89}
90
98WINPR_ATTR_NODISCARD static inline BOOL rdpgfx_server_packet_complete_header(wStream* s,
99 size_t start)
100{
101 const size_t current = Stream_GetPosition(s);
102 const size_t cap = Stream_Capacity(s);
103 if (cap < start + RDPGFX_HEADER_SIZE)
104 return FALSE;
105 if ((start > UINT32_MAX) || (current < start))
106 return FALSE;
107 /* Fill actual length */
108 if (!Stream_SetPosition(s, start + RDPGFX_HEADER_SIZE - sizeof(UINT32)))
109 return FALSE;
110 Stream_Write_UINT32(s, (UINT32)(current - start)); /* pduLength (4 bytes) */
111 return Stream_SetPosition(s, current);
112}
113
121WINPR_ATTR_NODISCARD static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s)
122{
123 UINT error = 0;
124 UINT32 flags = 0;
125 ULONG written = 0;
126 BYTE* pSrcData = Stream_Buffer(s);
127 const size_t SrcSize = Stream_GetPosition(s);
128 if (SrcSize > UINT32_MAX)
129 return ERROR_INTERNAL_ERROR;
130
131 WINPR_ASSERT(context);
132 WINPR_ASSERT(context->priv);
133
134 /* Allocate new stream with enough capacity. Additional overhead is
135 * descriptor (1 bytes) + segmentCount (2 bytes) + uncompressedSize (4 bytes)
136 * + segmentCount * size (4 bytes) */
137 wStream* fs = Stream_New(nullptr, SrcSize + 7 + (SrcSize / ZGFX_SEGMENTED_MAXSIZE + 1) * 4);
138
139 if (!fs)
140 {
141 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
142 error = CHANNEL_RC_NO_MEMORY;
143 goto out;
144 }
145
146 if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, (UINT32)SrcSize, &flags) < 0)
147 {
148 WLog_Print(context->priv->log, WLOG_ERROR, "zgfx_compress_to_stream failed!");
149 error = ERROR_INTERNAL_ERROR;
150 goto out;
151 }
152
153 {
154 const size_t pos = Stream_GetPosition(fs);
155 WINPR_ASSERT(pos <= UINT32_MAX);
156 if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, Stream_BufferAs(fs, char),
157 (UINT32)pos, &written))
158 {
159 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelWrite failed!");
160 error = ERROR_INTERNAL_ERROR;
161 goto out;
162 }
163 }
164
165 if (written < Stream_GetPosition(fs))
166 {
167 WLog_Print(context->priv->log, WLOG_WARN,
168 "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
169 Stream_GetPosition(fs));
170 }
171
172 error = CHANNEL_RC_OK;
173out:
174 Stream_Free(fs, TRUE);
175 Stream_Free(s, TRUE);
176 return error;
177}
178
191WINPR_ATTR_MALLOC(Stream_Free, 1)
192static wStream* rdpgfx_server_single_packet_new(wLog* log, UINT16 cmdId, size_t dataLen)
193{
194 UINT error = 0;
195 const size_t pduLength = rdpgfx_pdu_length(dataLen);
196 wStream* s = Stream_New(nullptr, pduLength);
197
198 if (!s)
199 {
200 WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
201 goto error;
202 }
203
204 if ((error = rdpgfx_server_packet_init_header(s, cmdId, pduLength)))
205 {
206 WLog_Print(log, WLOG_ERROR, "Failed to init header with error %" PRIu32 "!", error);
207 goto error;
208 }
209
210 return s;
211error:
212 Stream_Free(s, TRUE);
213 return nullptr;
214}
215
224WINPR_ATTR_NODISCARD static inline UINT
225rdpgfx_server_single_packet_send(RdpgfxServerContext* context, wStream* s)
226{
227 /* Fill actual length */
228 if (!rdpgfx_server_packet_complete_header(s, 0))
229 return ERROR_INTERNAL_ERROR;
230 return rdpgfx_server_packet_send(context, s);
231}
232
238WINPR_ATTR_NODISCARD static UINT
239rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context,
240 const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm)
241{
242 WINPR_ASSERT(context);
243 WINPR_ASSERT(context->priv);
244 WINPR_ASSERT(capsConfirm);
245
246 RDPGFX_CAPSET* capsSet = capsConfirm->capsSet;
247 WINPR_ASSERT(capsSet);
248
249 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CAPSCONFIRM,
250 RDPGFX_CAPSET_BASE_SIZE + capsSet->length);
251
252 if (!s)
253 {
254 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
255 return CHANNEL_RC_NO_MEMORY;
256 }
257
258 WLog_Print(context->priv->log, WLOG_DEBUG,
259 "CAPS version=0x%04" PRIx32 ", flags=0x%04" PRIx32 ", length=%" PRIu32,
260 capsSet->version, capsSet->flags, capsSet->length);
261 Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */
262 Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
263
264 if (capsSet->length >= 4)
265 {
266 Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
267 Stream_Zero(s, capsSet->length - 4);
268 }
269 else
270 Stream_Zero(s, capsSet->length);
271
272 context->priv->activeCapSet = *capsSet;
273 return rdpgfx_server_single_packet_send(context, s);
274}
275
281WINPR_ATTR_NODISCARD static UINT
282rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context, const RDPGFX_RESET_GRAPHICS_PDU* pdu)
283{
284 const size_t RDPGFX_RESET_GRAPHICS_PDU_SIZE = 340;
285
286 if (!checkCapsAreExchanged(context))
287 return CHANNEL_RC_NOT_INITIALIZED;
288
289 WINPR_ASSERT(pdu);
290 WINPR_ASSERT(context->priv);
291
292 /* Check monitorCount. This ensures total size within 340 bytes) */
293 if (pdu->monitorCount >= 16)
294 {
295 WLog_Print(context->priv->log, WLOG_ERROR,
296 "Monitor count MUST be less than or equal to 16: %" PRIu32 "",
297 pdu->monitorCount);
298 return ERROR_INVALID_DATA;
299 }
300
301 wStream* s =
302 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_RESETGRAPHICS,
303 RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE);
304
305 if (!s)
306 {
307 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
308 return CHANNEL_RC_NO_MEMORY;
309 }
310
311 Stream_Write_UINT32(s, pdu->width); /* width (4 bytes) */
312 Stream_Write_UINT32(s, pdu->height); /* height (4 bytes) */
313 Stream_Write_UINT32(s, pdu->monitorCount); /* monitorCount (4 bytes) */
314
315 for (UINT32 index = 0; index < pdu->monitorCount; index++)
316 {
317 const MONITOR_DEF* monitor = &(pdu->monitorDefArray[index]);
318 Stream_Write_INT32(s, monitor->left); /* left (4 bytes) */
319 Stream_Write_INT32(s, monitor->top); /* top (4 bytes) */
320 Stream_Write_INT32(s, monitor->right); /* right (4 bytes) */
321 Stream_Write_INT32(s, monitor->bottom); /* bottom (4 bytes) */
322 Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */
323 }
324
325 /* pad (total size must be 340 bytes) */
326 const size_t pos = Stream_GetPosition(s);
327 if (pos > RDPGFX_RESET_GRAPHICS_PDU_SIZE)
328 {
329 Stream_Free(s, TRUE);
330 return ERROR_INVALID_DATA;
331 }
332 if (!Stream_SafeSeek(s, RDPGFX_RESET_GRAPHICS_PDU_SIZE - pos))
333 {
334 Stream_Free(s, TRUE);
335 return ERROR_INVALID_DATA;
336 }
337 return rdpgfx_server_single_packet_send(context, s);
338}
339
345WINPR_ATTR_NODISCARD static UINT
346rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context,
348{
349 if (!checkCapsAreExchanged(context))
350 return CHANNEL_RC_NOT_INITIALIZED;
351
352 WINPR_ASSERT(pdu);
353 WINPR_ASSERT(context->priv);
354 wStream* s =
355 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_EVICTCACHEENTRY, 2);
356
357 if (!s)
358 {
359 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
360 return CHANNEL_RC_NO_MEMORY;
361 }
362
363 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
364 return rdpgfx_server_single_packet_send(context, s);
365}
366
372WINPR_ATTR_NODISCARD static UINT
373rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context,
375{
376 if (!checkCapsAreExchanged(context))
377 return CHANNEL_RC_NOT_INITIALIZED;
378 WINPR_ASSERT(context);
379 WINPR_ASSERT(context->priv);
380 WINPR_ASSERT(pdu);
381
382 WLog_Print(context->priv->log, WLOG_DEBUG, "reply with %" PRIu16 " entries",
383 pdu->importedEntriesCount);
384 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHEIMPORTREPLY,
385 2 + 2 * pdu->importedEntriesCount);
386
387 if (!s)
388 {
389 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
390 return CHANNEL_RC_NO_MEMORY;
391 }
392
393 /* importedEntriesCount (2 bytes) */
394 Stream_Write_UINT16(s, pdu->importedEntriesCount);
395
396 for (UINT16 index = 0; index < pdu->importedEntriesCount; index++)
397 {
398 Stream_Write_UINT16(s, pdu->cacheSlots[index]); /* cacheSlot (2 bytes) */
399 }
400
401 return rdpgfx_server_single_packet_send(context, s);
402}
403
404WINPR_ATTR_NODISCARD static UINT
405rdpgfx_process_cache_import_offer_pdu(RdpgfxServerContext* context,
406 const RDPGFX_CACHE_IMPORT_OFFER_PDU* cacheImportOffer)
407{
408 if (!checkCapsAreExchanged(context))
409 return CHANNEL_RC_NOT_INITIALIZED;
410 WINPR_ASSERT(context);
411 WINPR_ASSERT(context->priv);
412 WINPR_ASSERT(cacheImportOffer);
413
414 RDPGFX_CACHE_IMPORT_REPLY_PDU reply = WINPR_C_ARRAY_INIT;
415 WLog_Print(context->priv->log, WLOG_DEBUG,
416 "received %" PRIu16 " entries, reply with %" PRIu16 " entries",
417 cacheImportOffer->cacheEntriesCount, reply.importedEntriesCount);
418 return IFCALLRESULT(CHANNEL_RC_OK, context->CacheImportReply, context, &reply);
419}
420
426WINPR_ATTR_NODISCARD static UINT
427rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context, const RDPGFX_CREATE_SURFACE_PDU* pdu)
428{
429 if (!checkCapsAreExchanged(context))
430 return CHANNEL_RC_NOT_INITIALIZED;
431
432 WINPR_ASSERT(context->priv);
433 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CREATESURFACE, 7);
434
435 WINPR_ASSERT(context);
436 WINPR_ASSERT(pdu);
437 WINPR_ASSERT((pdu->pixelFormat == GFX_PIXEL_FORMAT_XRGB_8888) ||
438 (pdu->pixelFormat == GFX_PIXEL_FORMAT_ARGB_8888));
439
440 if (!s)
441 {
442 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
443 return CHANNEL_RC_NO_MEMORY;
444 }
445
446 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
447 Stream_Write_UINT16(s, pdu->width); /* width (2 bytes) */
448 Stream_Write_UINT16(s, pdu->height); /* height (2 bytes) */
449 Stream_Write_UINT8(s, pdu->pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */
450 return rdpgfx_server_single_packet_send(context, s);
451}
452
458WINPR_ATTR_NODISCARD static UINT
459rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context, const RDPGFX_DELETE_SURFACE_PDU* pdu)
460{
461 if (!checkCapsAreExchanged(context))
462 return CHANNEL_RC_NOT_INITIALIZED;
463
464 WINPR_ASSERT(pdu);
465 WINPR_ASSERT(context->priv);
466 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETESURFACE, 2);
467
468 if (!s)
469 {
470 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
471 return CHANNEL_RC_NO_MEMORY;
472 }
473
474 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
475 return rdpgfx_server_single_packet_send(context, s);
476}
477
478WINPR_ATTR_NODISCARD static inline BOOL
479rdpgfx_write_start_frame_pdu(wStream* s, const RDPGFX_START_FRAME_PDU* pdu)
480{
481 if (!Stream_EnsureRemainingCapacity(s, 8))
482 return FALSE;
483
484 WINPR_ASSERT(pdu);
485 Stream_Write_UINT32(s, pdu->timestamp); /* timestamp (4 bytes) */
486 Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
487 return TRUE;
488}
489
490WINPR_ATTR_NODISCARD static inline BOOL rdpgfx_write_end_frame_pdu(wStream* s,
491 const RDPGFX_END_FRAME_PDU* pdu)
492{
493 if (!Stream_EnsureRemainingCapacity(s, 4))
494 return FALSE;
495 WINPR_ASSERT(pdu);
496 Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
497 return TRUE;
498}
499
505WINPR_ATTR_NODISCARD static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context,
506 const RDPGFX_START_FRAME_PDU* pdu)
507{
508 if (!checkCapsAreExchanged(context))
509 return CHANNEL_RC_NOT_INITIALIZED;
510
511 WINPR_ASSERT(pdu);
512 WINPR_ASSERT(context->priv);
513 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_STARTFRAME,
514 RDPGFX_START_FRAME_PDU_SIZE);
515
516 if (!s)
517 {
518 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
519 return CHANNEL_RC_NO_MEMORY;
520 }
521
522 if (!rdpgfx_write_start_frame_pdu(s, pdu))
523 {
524 Stream_Free(s, TRUE);
525 return ERROR_INTERNAL_ERROR;
526 }
527 return rdpgfx_server_single_packet_send(context, s);
528}
529
535WINPR_ATTR_NODISCARD static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context,
536 const RDPGFX_END_FRAME_PDU* pdu)
537{
538 if (!checkCapsAreExchanged(context))
539 return CHANNEL_RC_NOT_INITIALIZED;
540
541 WINPR_ASSERT(pdu);
542 WINPR_ASSERT(context->priv);
543 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_ENDFRAME,
544 RDPGFX_END_FRAME_PDU_SIZE);
545
546 if (!s)
547 {
548 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
549 return CHANNEL_RC_NO_MEMORY;
550 }
551
552 if (!rdpgfx_write_end_frame_pdu(s, pdu))
553 {
554 Stream_Free(s, TRUE);
555 return ERROR_INTERNAL_ERROR;
556 }
557 return rdpgfx_server_single_packet_send(context, s);
558}
559
566WINPR_ATTR_NODISCARD static inline UINT32
567rdpgfx_estimate_h264_avc420(const RDPGFX_AVC420_BITMAP_STREAM* havc420)
568{
569 WINPR_ASSERT(havc420);
570 /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
571 return sizeof(UINT32) /* numRegionRects */
572 + 10ULL /* regionRects + quantQualityVals */
573 * havc420->meta.numRegionRects +
574 havc420->length;
575}
576
583WINPR_ATTR_NODISCARD static inline UINT32
584rdpgfx_estimate_surface_command(const RDPGFX_SURFACE_COMMAND* cmd)
585{
586 RDPGFX_AVC420_BITMAP_STREAM* havc420 = nullptr;
587 RDPGFX_AVC444_BITMAP_STREAM* havc444 = nullptr;
588 UINT32 h264Size = 0;
589
590 WINPR_ASSERT(cmd);
591
592 /* Estimate stream size according to codec. */
593 switch (cmd->codecId)
594 {
595 case RDPGFX_CODECID_CAPROGRESSIVE:
596 case RDPGFX_CODECID_CAPROGRESSIVE_V2:
597 return RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE + cmd->length;
598
599 case RDPGFX_CODECID_AVC420:
600 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
601 h264Size = rdpgfx_estimate_h264_avc420(havc420);
602 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
603
604 case RDPGFX_CODECID_AVC444:
605 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
606 h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */
607 /* avc420EncodedBitstream1 */
608 havc420 = &(havc444->bitstream[0]);
609 h264Size += rdpgfx_estimate_h264_avc420(havc420);
610
611 /* avc420EncodedBitstream2 */
612 if (havc444->LC == 0)
613 {
614 havc420 = &(havc444->bitstream[1]);
615 h264Size += rdpgfx_estimate_h264_avc420(havc420);
616 }
617
618 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
619
620 default:
621 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + cmd->length;
622 }
623}
624
632WINPR_ATTR_NODISCARD static inline UINT16
633rdpgfx_surface_command_cmdid(const RDPGFX_SURFACE_COMMAND* cmd)
634{
635 WINPR_ASSERT(cmd);
636
637 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
638 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
639 {
640 return RDPGFX_CMDID_WIRETOSURFACE_2;
641 }
642
643 return RDPGFX_CMDID_WIRETOSURFACE_1;
644}
645
651WINPR_ATTR_NODISCARD static UINT rdpgfx_write_h264_metablock(wLog* log, wStream* s,
652 const RDPGFX_H264_METABLOCK* meta)
653{
654 RECTANGLE_16* regionRect = nullptr;
655 RDPGFX_H264_QUANT_QUALITY* quantQualityVal = nullptr;
656 UINT error = CHANNEL_RC_OK;
657
658 WINPR_ASSERT(meta);
659 if (!Stream_EnsureRemainingCapacity(s, 4 + meta->numRegionRects * 10))
660 return ERROR_OUTOFMEMORY;
661
662 Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
663
664 for (UINT32 index = 0; index < meta->numRegionRects; index++)
665 {
666 regionRect = &(meta->regionRects[index]);
667
668 if ((error = rdpgfx_write_rect16(s, regionRect)))
669 {
670 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_rect16 failed with error %" PRIu32 "!",
671 error);
672 return error;
673 }
674 }
675
676 for (UINT32 index = 0; index < meta->numRegionRects; index++)
677 {
678 quantQualityVal = &(meta->quantQualityVals[index]);
679 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(
680 uint8_t, quantQualityVal->qp | (quantQualityVal->r << 6) |
681 (quantQualityVal->p << 7))); /* qpVal (1 byte) */
682 /* qualityVal (1 byte) */
683 Stream_Write_UINT8(s, quantQualityVal->qualityVal);
684 }
685
686 return error;
687}
688
695WINPR_ATTR_NODISCARD static inline UINT
696rdpgfx_write_h264_avc420(wLog* log, wStream* s, RDPGFX_AVC420_BITMAP_STREAM* havc420)
697{
698 WINPR_ASSERT(havc420);
699 const UINT error = rdpgfx_write_h264_metablock(log, s, &(havc420->meta));
700
701 if (error != CHANNEL_RC_OK)
702 {
703 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_metablock failed with error %" PRIu32 "!",
704 error);
705 return error;
706 }
707
708 if (!Stream_EnsureRemainingCapacity(s, havc420->length))
709 return ERROR_OUTOFMEMORY;
710
711 Stream_Write(s, havc420->data, havc420->length);
712 return error;
713}
714
722WINPR_ATTR_NODISCARD static UINT rdpgfx_write_surface_command(wLog* log, wStream* s,
723 const RDPGFX_SURFACE_COMMAND* cmd)
724{
725 UINT error = CHANNEL_RC_OK;
726 RDPGFX_AVC420_BITMAP_STREAM* havc420 = nullptr;
727 RDPGFX_AVC444_BITMAP_STREAM* havc444 = nullptr;
728 UINT8 pixelFormat = 0;
729
730 WINPR_ASSERT(cmd);
731 switch (cmd->format)
732 {
733 case PIXEL_FORMAT_BGRX32:
734 pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
735 break;
736
737 case PIXEL_FORMAT_BGRA32:
738 pixelFormat = GFX_PIXEL_FORMAT_ARGB_8888;
739 break;
740
741 default:
742 WLog_Print(log, WLOG_ERROR, "Format %s not supported!",
743 FreeRDPGetColorFormatName(cmd->format));
744 return ERROR_INVALID_DATA;
745 }
746
747 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
748 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
749 {
750 if (!Stream_EnsureRemainingCapacity(s, 13 + cmd->length))
751 return ERROR_INTERNAL_ERROR;
752 /* Write RDPGFX_CMDID_WIRETOSURFACE_2 format for CAPROGRESSIVE */
753 Stream_Write_UINT16(
754 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->surfaceId)); /* surfaceId (2 bytes) */
755 Stream_Write_UINT16(
756 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->codecId)); /* codecId (2 bytes) */
757 Stream_Write_UINT32(s, cmd->contextId); /* codecContextId (4 bytes) */
758 Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */
759 Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */
760 Stream_Write(s, cmd->data, cmd->length);
761 }
762 else
763 {
764 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 format for others */
765 if (!Stream_EnsureRemainingCapacity(s, 17))
766 return ERROR_INTERNAL_ERROR;
767 Stream_Write_UINT16(
768 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->surfaceId)); /* surfaceId (2 bytes) */
769 Stream_Write_UINT16(
770 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->codecId)); /* codecId (2 bytes) */
771 Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */
772 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->left)); /* left (2 bytes) */
773 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->top)); /* top (2 bytes) */
774 Stream_Write_UINT16(s,
775 WINPR_ASSERTING_INT_CAST(uint16_t, cmd->right)); /* right (2 bytes) */
776 Stream_Write_UINT16(s,
777 WINPR_ASSERTING_INT_CAST(uint16_t, cmd->bottom)); /* bottom (2 bytes) */
778 Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */
779 const size_t bitmapDataStart = Stream_GetPosition(s);
780
781 if (cmd->codecId == RDPGFX_CODECID_AVC420)
782 {
783 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
784 error = rdpgfx_write_h264_avc420(log, s, havc420);
785
786 if (error != CHANNEL_RC_OK)
787 {
788 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
789 return error;
790 }
791 }
792 else if ((cmd->codecId == RDPGFX_CODECID_AVC444) ||
793 (cmd->codecId == RDPGFX_CODECID_AVC444v2))
794 {
795 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
796 havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */
797 if (!Stream_EnsureRemainingCapacity(s, 4))
798 return ERROR_INTERNAL_ERROR;
799 Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 |
800 ((uint32_t)havc444->LC << 30UL));
801 /* avc420EncodedBitstream1 */
802 error = rdpgfx_write_h264_avc420(log, s, havc420);
803
804 if (error != CHANNEL_RC_OK)
805 {
806 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
807 return error;
808 }
809
810 /* avc420EncodedBitstream2 */
811 if (havc444->LC == 0)
812 {
813 havc420 = &(havc444->bitstream[1]);
814 error = rdpgfx_write_h264_avc420(log, s, havc420);
815
816 if (error != CHANNEL_RC_OK)
817 {
818 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
819 return error;
820 }
821 }
822 }
823 else
824 {
825 if (!Stream_EnsureRemainingCapacity(s, cmd->length))
826 return ERROR_INTERNAL_ERROR;
827 Stream_Write(s, cmd->data, cmd->length);
828 }
829
830 /* Fill actual bitmap data length */
831 const size_t bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart;
832 if (bitmapDataLength > UINT32_MAX)
833 return ERROR_INTERNAL_ERROR;
834
835 if (!Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32)))
836 return ERROR_INVALID_DATA;
837 if (!Stream_EnsureRemainingCapacity(s, 4))
838 return ERROR_INTERNAL_ERROR;
839 Stream_Write_UINT32(s, (UINT32)bitmapDataLength); /* bitmapDataLength (4 bytes) */
840 if (!Stream_SafeSeek(s, bitmapDataLength))
841 return ERROR_INTERNAL_ERROR;
842 }
843
844 return error;
845}
846
854WINPR_ATTR_NODISCARD static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context,
855 const RDPGFX_SURFACE_COMMAND* cmd)
856{
857 if (!checkCapsAreExchanged(context))
858 return CHANNEL_RC_NOT_INITIALIZED;
859 UINT error = CHANNEL_RC_OK;
860
861 WINPR_ASSERT(context);
862 WINPR_ASSERT(context->priv);
863 WINPR_ASSERT(cmd);
864
865 wStream* s =
866 rdpgfx_server_single_packet_new(context->priv->log, rdpgfx_surface_command_cmdid(cmd),
867 rdpgfx_estimate_surface_command(cmd));
868
869 if (!s)
870 {
871 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
872 return CHANNEL_RC_NO_MEMORY;
873 }
874
875 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
876
877 if (error != CHANNEL_RC_OK)
878 {
879 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
880 goto error;
881 }
882
883 return rdpgfx_server_single_packet_send(context, s);
884error:
885 Stream_Free(s, TRUE);
886 return error;
887}
888
897WINPR_ATTR_NODISCARD static UINT
898rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, const RDPGFX_SURFACE_COMMAND* cmd,
899 const RDPGFX_START_FRAME_PDU* startFrame,
900 const RDPGFX_END_FRAME_PDU* endFrame)
901
902{
903 if (!checkCapsAreExchanged(context))
904 return CHANNEL_RC_NOT_INITIALIZED;
905
906 WINPR_ASSERT(context->priv);
907 WINPR_ASSERT(cmd);
908 WINPR_ASSERT(startFrame);
909 WINPR_ASSERT(endFrame);
910
911 UINT error = CHANNEL_RC_OK;
912 size_t size = rdpgfx_pdu_length(rdpgfx_estimate_surface_command(cmd));
913
914 if (startFrame)
915 {
916 size += rdpgfx_pdu_length(RDPGFX_START_FRAME_PDU_SIZE);
917 }
918
919 if (endFrame)
920 {
921 size += rdpgfx_pdu_length(RDPGFX_END_FRAME_PDU_SIZE);
922 }
923
924 wStream* s = Stream_New(nullptr, size);
925
926 if (!s)
927 {
928 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
929 return CHANNEL_RC_NO_MEMORY;
930 }
931
932 /* Write start frame if exists */
933 if (startFrame)
934 {
935 const size_t position = Stream_GetPosition(s);
936 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_STARTFRAME, 0);
937
938 if (error != CHANNEL_RC_OK)
939 {
940 WLog_Print(context->priv->log, WLOG_ERROR,
941 "Failed to init header with error %" PRIu32 "!", error);
942 goto error;
943 }
944
945 if (!rdpgfx_write_start_frame_pdu(s, startFrame) ||
946 !rdpgfx_server_packet_complete_header(s, position))
947 goto error;
948 }
949
950 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */
951 {
952 const size_t pos = Stream_GetPosition(s);
953 error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd),
954 0); // Actual length will be filled later
955
956 if (error != CHANNEL_RC_OK)
957 {
958 WLog_Print(context->priv->log, WLOG_ERROR,
959 "Failed to init header with error %" PRIu32 "!", error);
960 goto error;
961 }
962
963 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
964
965 if (error != CHANNEL_RC_OK)
966 {
967 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
968 goto error;
969 }
970
971 if (!rdpgfx_server_packet_complete_header(s, pos))
972 goto error;
973 }
974
975 /* Write end frame if exists */
976 if (endFrame)
977 {
978 const size_t position = Stream_GetPosition(s);
979 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0);
980
981 if (error != CHANNEL_RC_OK)
982 {
983 WLog_Print(context->priv->log, WLOG_ERROR,
984 "Failed to init header with error %" PRIu32 "!", error);
985 goto error;
986 }
987
988 if (!rdpgfx_write_end_frame_pdu(s, endFrame) ||
989 !rdpgfx_server_packet_complete_header(s, position))
990 goto error;
991 }
992
993 return rdpgfx_server_packet_send(context, s);
994error:
995 Stream_Free(s, TRUE);
996 return error;
997}
998
1004WINPR_ATTR_NODISCARD static UINT
1005rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context,
1007{
1008 if (!checkCapsAreExchanged(context))
1009 return CHANNEL_RC_NOT_INITIALIZED;
1010
1011 WINPR_ASSERT(context->priv);
1012 WINPR_ASSERT(pdu);
1013 wStream* s =
1014 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6);
1015
1016 if (!s)
1017 {
1018 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1019 return CHANNEL_RC_NO_MEMORY;
1020 }
1021
1022 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1023 Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */
1024 return rdpgfx_server_single_packet_send(context, s);
1025}
1026
1032WINPR_ATTR_NODISCARD static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context,
1033 const RDPGFX_SOLID_FILL_PDU* pdu)
1034{
1035 if (!checkCapsAreExchanged(context))
1036 return CHANNEL_RC_NOT_INITIALIZED;
1037
1038 WINPR_ASSERT(context->priv);
1039 WINPR_ASSERT(pdu);
1040
1041 UINT error = CHANNEL_RC_OK;
1042 RECTANGLE_16* fillRect = nullptr;
1043 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SOLIDFILL,
1044 8 + 8 * pdu->fillRectCount);
1045
1046 if (!s)
1047 {
1048 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1049 return CHANNEL_RC_NO_MEMORY;
1050 }
1051
1052 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1053
1054 /* fillPixel (4 bytes) */
1055 if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel))))
1056 {
1057 WLog_Print(context->priv->log, WLOG_ERROR,
1058 "rdpgfx_write_color32 failed with error %" PRIu32 "!", error);
1059 goto error;
1060 }
1061
1062 Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */
1063
1064 for (UINT16 index = 0; index < pdu->fillRectCount; index++)
1065 {
1066 fillRect = &(pdu->fillRects[index]);
1067
1068 if ((error = rdpgfx_write_rect16(s, fillRect)))
1069 {
1070 WLog_Print(context->priv->log, WLOG_ERROR,
1071 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1072 goto error;
1073 }
1074 }
1075
1076 return rdpgfx_server_single_packet_send(context, s);
1077error:
1078 Stream_Free(s, TRUE);
1079 return error;
1080}
1081
1087WINPR_ATTR_NODISCARD static UINT
1088rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context,
1090{
1091 if (!checkCapsAreExchanged(context))
1092 return CHANNEL_RC_NOT_INITIALIZED;
1093
1094 WINPR_ASSERT(pdu);
1095 WINPR_ASSERT(context->priv);
1096
1097 UINT error = CHANNEL_RC_OK;
1098 RDPGFX_POINT16* destPt = nullptr;
1099 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOSURFACE,
1100 14 + 4 * pdu->destPtsCount);
1101
1102 if (!s)
1103 {
1104 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1105 return CHANNEL_RC_NO_MEMORY;
1106 }
1107
1108 Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
1109 Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */
1110
1111 /* rectSrc (8 bytes ) */
1112 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1113 {
1114 WLog_Print(context->priv->log, WLOG_ERROR,
1115 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1116 goto error;
1117 }
1118
1119 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1120
1121 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1122 {
1123 destPt = &(pdu->destPts[index]);
1124
1125 if ((error = rdpgfx_write_point16(s, destPt)))
1126 {
1127 WLog_Print(context->priv->log, WLOG_ERROR,
1128 "rdpgfx_write_point16 failed with error %" PRIu32 "!", error);
1129 goto error;
1130 }
1131 }
1132
1133 return rdpgfx_server_single_packet_send(context, s);
1134error:
1135 Stream_Free(s, TRUE);
1136 return error;
1137}
1138
1144WINPR_ATTR_NODISCARD static UINT
1145rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context,
1146 const RDPGFX_SURFACE_TO_CACHE_PDU* pdu)
1147{
1148 if (!checkCapsAreExchanged(context))
1149 return CHANNEL_RC_NOT_INITIALIZED;
1150
1151 WINPR_ASSERT(pdu);
1152 WINPR_ASSERT(context->priv);
1153
1154 UINT error = CHANNEL_RC_OK;
1155 wStream* s =
1156 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOCACHE, 20);
1157
1158 if (!s)
1159 {
1160 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1161 return CHANNEL_RC_NO_MEMORY;
1162 }
1163
1164 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1165 Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */
1166 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1167
1168 /* rectSrc (8 bytes ) */
1169 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1170 {
1171 WLog_Print(context->priv->log, WLOG_ERROR,
1172 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1173 goto error;
1174 }
1175
1176 return rdpgfx_server_single_packet_send(context, s);
1177error:
1178 Stream_Free(s, TRUE);
1179 return error;
1180}
1181
1187WINPR_ATTR_NODISCARD static UINT
1188rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context,
1189 const RDPGFX_CACHE_TO_SURFACE_PDU* pdu)
1190{
1191 if (!checkCapsAreExchanged(context))
1192 return CHANNEL_RC_NOT_INITIALIZED;
1193
1194 WINPR_ASSERT(pdu);
1195 WINPR_ASSERT(context->priv);
1196
1197 UINT error = CHANNEL_RC_OK;
1198 RDPGFX_POINT16* destPt = nullptr;
1199 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHETOSURFACE,
1200 6 + 4 * pdu->destPtsCount);
1201
1202 if (!s)
1203 {
1204 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1205 return CHANNEL_RC_NO_MEMORY;
1206 }
1207
1208 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1209 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1210 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1211
1212 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1213 {
1214 destPt = &(pdu->destPts[index]);
1215
1216 if ((error = rdpgfx_write_point16(s, destPt)))
1217 {
1218 WLog_Print(context->priv->log, WLOG_ERROR,
1219 "rdpgfx_write_point16 failed with error %" PRIu32 "", error);
1220 goto error;
1221 }
1222 }
1223
1224 return rdpgfx_server_single_packet_send(context, s);
1225error:
1226 Stream_Free(s, TRUE);
1227 return error;
1228}
1229
1235WINPR_ATTR_NODISCARD static UINT
1236rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context,
1238{
1239 if (!checkCapsAreExchanged(context))
1240 return CHANNEL_RC_NOT_INITIALIZED;
1241
1242 WINPR_ASSERT(pdu);
1243 WINPR_ASSERT(context->priv);
1244 wStream* s =
1245 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12);
1246
1247 if (!s)
1248 {
1249 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1250 return CHANNEL_RC_NO_MEMORY;
1251 }
1252
1253 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1254 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1255 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1256 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1257 return rdpgfx_server_single_packet_send(context, s);
1258}
1259
1265WINPR_ATTR_NODISCARD static UINT
1266rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context,
1268{
1269 if (!checkCapsAreExchanged(context))
1270 return CHANNEL_RC_NOT_INITIALIZED;
1271
1272 WINPR_ASSERT(pdu);
1273 WINPR_ASSERT(context->priv);
1274
1275 wStream* s =
1276 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOWINDOW, 18);
1277
1278 if (!s)
1279 {
1280 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1281 return CHANNEL_RC_NO_MEMORY;
1282 }
1283
1284 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1285 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1286 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1287 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1288 return rdpgfx_server_single_packet_send(context, s);
1289}
1290
1291WINPR_ATTR_NODISCARD static UINT
1292rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context,
1294{
1295 if (!checkCapsAreExchanged(context))
1296 return CHANNEL_RC_NOT_INITIALIZED;
1297
1298 WINPR_ASSERT(pdu);
1299 WINPR_ASSERT(context->priv);
1300 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1301 RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26);
1302
1303 if (!s)
1304 {
1305 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1306 return CHANNEL_RC_NO_MEMORY;
1307 }
1308
1309 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1310 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1311 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1312 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1313 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1314 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1315 return rdpgfx_server_single_packet_send(context, s);
1316}
1317
1323WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context,
1324 wStream* s)
1325{
1326 WINPR_ASSERT(context);
1327
1328 if (!checkCapsAreExchanged(context))
1329 return CHANNEL_RC_NOT_INITIALIZED;
1330
1331 WINPR_ASSERT(context->priv);
1332
1333 RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu = WINPR_C_ARRAY_INIT;
1334 UINT error = CHANNEL_RC_OK;
1335
1336 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1337 return ERROR_INVALID_DATA;
1338
1339 Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */
1340 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1341 Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
1342
1343 IFCALLRET(context->FrameAcknowledge, error, context, &pdu);
1344
1345 if (error)
1346 WLog_Print(context->priv->log, WLOG_ERROR,
1347 "context->FrameAcknowledge failed with error %" PRIu32 "", error);
1348
1349 return error;
1350}
1351
1357WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context,
1358 wStream* s)
1359{
1360 WINPR_ASSERT(context);
1361 if (!checkCapsAreExchanged(context))
1362 return CHANNEL_RC_NOT_INITIALIZED;
1363
1364 WINPR_ASSERT(context->priv);
1365
1366 RDPGFX_CACHE_IMPORT_OFFER_PDU pdu = WINPR_C_ARRAY_INIT;
1367 RDPGFX_CACHE_ENTRY_METADATA* cacheEntry = nullptr;
1368 UINT error = CHANNEL_RC_OK;
1369
1370 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1371 return ERROR_INVALID_DATA;
1372
1373 /* cacheEntriesCount (2 bytes) */
1374 Stream_Read_UINT16(s, pdu.cacheEntriesCount);
1375
1376 /* 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU */
1377 if (pdu.cacheEntriesCount >= 5462)
1378 {
1379 WLog_Print(context->priv->log, WLOG_ERROR, "Invalid cacheEntriesCount: %" PRIu16 "",
1380 pdu.cacheEntriesCount);
1381 return ERROR_INVALID_DATA;
1382 }
1383
1384 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(context->priv->log, s, pdu.cacheEntriesCount,
1385 12ull))
1386 return ERROR_INVALID_DATA;
1387
1388 for (UINT16 index = 0; index < pdu.cacheEntriesCount; index++)
1389 {
1390 cacheEntry = &(pdu.cacheEntries[index]);
1391 Stream_Read_UINT64(s, cacheEntry->cacheKey); /* cacheKey (8 bytes) */
1392 Stream_Read_UINT32(s, cacheEntry->bitmapLength); /* bitmapLength (4 bytes) */
1393 }
1394
1395 IFCALLRET(context->CacheImportOffer, error, context, &pdu);
1396
1397 if (error)
1398 WLog_Print(context->priv->log, WLOG_ERROR,
1399 "context->CacheImportOffer failed with error %" PRIu32 "", error);
1400
1401 return error;
1402}
1403
1409WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context,
1410 wStream* s)
1411{
1412 RDPGFX_CAPSET* capsSets = nullptr;
1413 RDPGFX_CAPS_ADVERTISE_PDU pdu = WINPR_C_ARRAY_INIT;
1414 UINT error = ERROR_INVALID_DATA;
1415
1416 if (!context)
1417 return ERROR_BAD_ARGUMENTS;
1418
1419 WINPR_ASSERT(context->priv);
1420 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1421 return ERROR_INVALID_DATA;
1422
1423 Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
1424 if (pdu.capsSetCount > 0)
1425 {
1426 capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4));
1427 if (!capsSets)
1428 return ERROR_OUTOFMEMORY;
1429 }
1430
1431 pdu.capsSets = capsSets;
1432
1433 for (UINT16 index = 0; index < pdu.capsSetCount; index++)
1434 {
1435 RDPGFX_CAPSET* capsSet = &(pdu.capsSets[index]);
1436
1437 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
1438 goto fail;
1439
1440 Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */
1441 Stream_Read_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
1442
1443 if (capsSet->length >= 4)
1444 {
1445 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1446 goto fail;
1447
1448 Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
1449 }
1450
1451 if (!Stream_SafeSeek(s, capsSet->length))
1452 goto fail;
1453 }
1454
1455 error = ERROR_BAD_CONFIGURATION;
1456 IFCALLRET(context->CapsAdvertise, error, context, &pdu);
1457
1458 if (error)
1459 WLog_Print(context->priv->log, WLOG_ERROR,
1460 "context->CapsAdvertise failed with error %" PRIu32 "", error);
1461
1462fail:
1463 free(capsSets);
1464 return error;
1465}
1466
1472WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context,
1473 wStream* s)
1474{
1475 WINPR_ASSERT(context);
1476
1477 if (!checkCapsAreExchanged(context))
1478 return CHANNEL_RC_NOT_INITIALIZED;
1479
1480 RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu = WINPR_C_ARRAY_INIT;
1481 UINT error = CHANNEL_RC_OK;
1482
1483 WINPR_ASSERT(context->priv);
1484
1485 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1486 return ERROR_INVALID_DATA;
1487
1488 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1489 Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
1490 Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */
1491 Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */
1492
1493 IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu);
1494
1495 if (error)
1496 WLog_Print(context->priv->log, WLOG_ERROR,
1497 "context->QoeFrameAcknowledge failed with error %" PRIu32 "", error);
1498
1499 return error;
1500}
1501
1502WINPR_ATTR_NODISCARD static UINT
1503rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context,
1505{
1506 if (!checkCapsAreExchanged(context))
1507 return CHANNEL_RC_NOT_INITIALIZED;
1508
1509 WINPR_ASSERT(pdu);
1510 WINPR_ASSERT(context->priv);
1511 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1512 RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20);
1513
1514 if (!s)
1515 {
1516 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1517 return CHANNEL_RC_NO_MEMORY;
1518 }
1519
1520 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1521 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1522 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1523 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1524 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1525 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1526 return rdpgfx_server_single_packet_send(context, s);
1527}
1528
1534WINPR_ATTR_NODISCARD static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
1535{
1536 size_t end = 0;
1537 RDPGFX_HEADER header = WINPR_C_ARRAY_INIT;
1538 UINT error = CHANNEL_RC_OK;
1539 size_t beg = Stream_GetPosition(s);
1540
1541 WINPR_ASSERT(context);
1542 WINPR_ASSERT(context->priv);
1543
1544 if ((error = rdpgfx_read_header(context->priv->log, s, &header)))
1545 {
1546 WLog_Print(context->priv->log, WLOG_ERROR,
1547 "rdpgfx_read_header failed with error %" PRIu32 "!", error);
1548 return error;
1549 }
1550
1551 WLog_Print(context->priv->log, WLOG_TRACE,
1552 "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "",
1553 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
1554 header.pduLength);
1555
1556 switch (header.cmdId)
1557 {
1558 case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
1559 if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
1560 WLog_Print(context->priv->log, WLOG_ERROR,
1561 "rdpgfx_recv_frame_acknowledge_pdu "
1562 "failed with error %" PRIu32 "!",
1563 error);
1564
1565 break;
1566
1567 case RDPGFX_CMDID_CACHEIMPORTOFFER:
1568 if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
1569 WLog_Print(context->priv->log, WLOG_ERROR,
1570 "rdpgfx_recv_cache_import_offer_pdu "
1571 "failed with error %" PRIu32 "!",
1572 error);
1573
1574 break;
1575
1576 case RDPGFX_CMDID_CAPSADVERTISE:
1577 if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
1578 WLog_Print(context->priv->log, WLOG_ERROR,
1579 "rdpgfx_recv_caps_advertise_pdu "
1580 "failed with error %" PRIu32 "!",
1581 error);
1582
1583 break;
1584
1585 case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
1586 if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
1587 WLog_Print(context->priv->log, WLOG_ERROR,
1588 "rdpgfx_recv_qoe_frame_acknowledge_pdu "
1589 "failed with error %" PRIu32 "!",
1590 error);
1591
1592 break;
1593
1594 default:
1595 error = CHANNEL_RC_BAD_PROC;
1596 break;
1597 }
1598
1599 if (error)
1600 {
1601 WLog_Print(context->priv->log, WLOG_ERROR,
1602 "Error while parsing GFX cmdId: %s (0x%04" PRIX16 ")",
1603 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
1604 return error;
1605 }
1606
1607 end = Stream_GetPosition(s);
1608
1609 if (end != (beg + header.pduLength))
1610 {
1611 WLog_Print(context->priv->log, WLOG_ERROR,
1612 "Unexpected gfx pdu end: Actual: %" PRIuz ", Expected: %" PRIuz "", end,
1613 (beg + header.pduLength));
1614 if (!Stream_SetPosition(s, (beg + header.pduLength)))
1615 return ERROR_INVALID_DATA;
1616 }
1617
1618 return error;
1619}
1620
1621WINPR_ATTR_NODISCARD static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
1622{
1623 RdpgfxServerContext* context = (RdpgfxServerContext*)arg;
1624 WINPR_ASSERT(context);
1625
1626 RdpgfxServerPrivate* priv = context->priv;
1627 DWORD status = 0;
1628 DWORD nCount = 0;
1629 HANDLE events[8] = WINPR_C_ARRAY_INIT;
1630 UINT error = CHANNEL_RC_OK;
1631
1632 WINPR_ASSERT(priv);
1633
1634 if (priv->ownThread)
1635 {
1636 WINPR_ASSERT(priv->stopEvent);
1637 events[nCount++] = priv->stopEvent;
1638 }
1639
1640 WINPR_ASSERT(priv->channelEvent);
1641 events[nCount++] = priv->channelEvent;
1642
1643 /* Main virtual channel loop. RDPGFX do not need version negotiation */
1644 while (TRUE)
1645 {
1646 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1647
1648 if (status == WAIT_FAILED)
1649 {
1650 error = GetLastError();
1651 WLog_Print(context->priv->log, WLOG_ERROR,
1652 "WaitForMultipleObjects failed with error %" PRIu32 "", error);
1653 break;
1654 }
1655
1656 /* Stop Event */
1657 if (status == WAIT_OBJECT_0)
1658 break;
1659
1660 if ((error = rdpgfx_server_handle_messages(context)))
1661 {
1662 WLog_Print(context->priv->log, WLOG_ERROR,
1663 "rdpgfx_server_handle_messages failed with error %" PRIu32 "", error);
1664 break;
1665 }
1666 }
1667
1668 if (error && context->rdpcontext)
1669 setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error");
1670
1671 ExitThread(error);
1672 return error;
1673}
1674
1675WINPR_ATTR_NODISCARD static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
1676{
1677 WINPR_ASSERT(context);
1678 RdpgfxServerPrivate* priv = context->priv;
1679 void* buffer = nullptr;
1680
1681 WINPR_ASSERT(priv);
1682
1683 if (!priv->isOpened)
1684 {
1685 PULONG pSessionId = nullptr;
1686 DWORD BytesReturned = 0;
1687 priv->SessionId = WTS_CURRENT_SESSION;
1688 UINT32 channelId = 0;
1689 BOOL status = TRUE;
1690
1691 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
1692 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
1693 {
1694 WLog_Print(context->priv->log, WLOG_ERROR, "WTSQuerySessionInformationA failed!");
1695 return FALSE;
1696 }
1697
1698 priv->SessionId = (DWORD)*pSessionId;
1699 WTSFreeMemory(pSessionId);
1700 priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME,
1701 WTS_CHANNEL_OPTION_DYNAMIC);
1702
1703 if (!priv->rdpgfx_channel)
1704 {
1705 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelOpenEx failed!");
1706 return FALSE;
1707 }
1708
1709 channelId = WTSChannelGetIdByHandle(priv->rdpgfx_channel);
1710
1711 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
1712 if (!status)
1713 {
1714 WLog_Print(context->priv->log, WLOG_ERROR, "context->ChannelIdAssigned failed!");
1715 goto fail;
1716 }
1717
1718 /* Query for channel event handle */
1719 if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
1720 &BytesReturned) ||
1721 (BytesReturned != sizeof(HANDLE)))
1722 {
1723 WLog_Print(context->priv->log, WLOG_ERROR,
1724 "WTSVirtualChannelQuery failed "
1725 "or invalid returned size(%" PRIu32 ")",
1726 BytesReturned);
1727
1728 if (buffer)
1729 WTSFreeMemory(buffer);
1730
1731 goto fail;
1732 }
1733
1734 priv->channelEvent = *(HANDLE*)buffer;
1735 WTSFreeMemory(buffer);
1736
1737 if (!(priv->zgfx = zgfx_context_new(TRUE)))
1738 {
1739 WLog_Print(context->priv->log, WLOG_ERROR, "Create zgfx context failed!");
1740 goto fail;
1741 }
1742
1743 priv->isReady = FALSE;
1744 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1745 priv->activeCapSet = empty;
1746 if (priv->ownThread)
1747 {
1748 if (!(priv->stopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
1749 {
1750 WLog_Print(context->priv->log, WLOG_ERROR, "CreateEvent failed!");
1751 goto fail;
1752 }
1753
1754 if (!(priv->thread = CreateThread(nullptr, 0, rdpgfx_server_thread_func, (void*)context,
1755 0, nullptr)))
1756 {
1757 WLog_Print(context->priv->log, WLOG_ERROR, "CreateThread failed!");
1758 goto fail;
1759 }
1760 }
1761
1762 priv->isOpened = TRUE;
1763 return TRUE;
1764 }
1765
1766 WLog_Print(context->priv->log, WLOG_ERROR, "RDPGFX channel is already opened!");
1767 return FALSE;
1768fail:
1769 (void)rdpgfx_server_close(context);
1770 return FALSE;
1771}
1772
1773BOOL rdpgfx_server_close(RdpgfxServerContext* context)
1774{
1775 WINPR_ASSERT(context);
1776
1777 RdpgfxServerPrivate* priv = context->priv;
1778 WINPR_ASSERT(priv);
1779
1780 if (priv->ownThread && priv->thread)
1781 {
1782 (void)SetEvent(priv->stopEvent);
1783
1784 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
1785 {
1786 WLog_Print(context->priv->log, WLOG_ERROR,
1787 "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
1788 return FALSE;
1789 }
1790
1791 (void)CloseHandle(priv->thread);
1792 (void)CloseHandle(priv->stopEvent);
1793 priv->thread = nullptr;
1794 priv->stopEvent = nullptr;
1795 }
1796
1797 zgfx_context_free(priv->zgfx);
1798 priv->zgfx = nullptr;
1799
1800 if (priv->rdpgfx_channel)
1801 {
1802 (void)WTSVirtualChannelClose(priv->rdpgfx_channel);
1803 priv->rdpgfx_channel = nullptr;
1804 }
1805
1806 priv->channelEvent = nullptr;
1807 priv->isOpened = FALSE;
1808 priv->isReady = FALSE;
1809 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1810 priv->activeCapSet = empty;
1811 return TRUE;
1812}
1813
1814WINPR_ATTR_NODISCARD static BOOL rdpgfx_server_initialize(RdpgfxServerContext* context,
1815 BOOL externalThread)
1816{
1817 WINPR_ASSERT(context);
1818 WINPR_ASSERT(context->priv);
1819
1820 if (context->priv->isOpened)
1821 {
1822 WLog_Print(context->priv->log, WLOG_WARN,
1823 "Application error: RDPEGFX channel already initialized, "
1824 "calling in this state is not possible!");
1825 return FALSE;
1826 }
1827
1828 context->priv->ownThread = !externalThread;
1829 return TRUE;
1830}
1831
1832RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm)
1833{
1834 RdpgfxServerContext* context = (RdpgfxServerContext*)calloc(1, sizeof(RdpgfxServerContext));
1835
1836 if (!context)
1837 return nullptr;
1838
1839 context->vcm = vcm;
1840 context->Initialize = rdpgfx_server_initialize;
1841 context->Open = rdpgfx_server_open;
1842 context->Close = rdpgfx_server_close;
1843 context->ResetGraphics = rdpgfx_send_reset_graphics_pdu;
1844 context->StartFrame = rdpgfx_send_start_frame_pdu;
1845 context->EndFrame = rdpgfx_send_end_frame_pdu;
1846 context->SurfaceCommand = rdpgfx_send_surface_command;
1847 context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command;
1848 context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu;
1849 context->CreateSurface = rdpgfx_send_create_surface_pdu;
1850 context->DeleteSurface = rdpgfx_send_delete_surface_pdu;
1851 context->SolidFill = rdpgfx_send_solid_fill_pdu;
1852 context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu;
1853 context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu;
1854 context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu;
1855 context->CacheImportOffer = rdpgfx_process_cache_import_offer_pdu;
1856 context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu;
1857 context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu;
1858 context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu;
1859 context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu;
1860 context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu;
1861 context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu;
1862 context->CapsAdvertise = nullptr;
1863 context->CapsConfirm = rdpgfx_send_caps_confirm_pdu;
1864 context->FrameAcknowledge = nullptr;
1865 context->QoeFrameAcknowledge = nullptr;
1866 RdpgfxServerPrivate* priv = context->priv =
1867 (RdpgfxServerPrivate*)calloc(1, sizeof(RdpgfxServerPrivate));
1868
1869 if (!priv)
1870 goto fail;
1871
1872 priv->log = WLog_Get(TAG);
1873 if (!priv->log)
1874 goto fail;
1875
1876 /* Create shared input stream */
1877 priv->input_stream = Stream_New(nullptr, 4);
1878
1879 if (!priv->input_stream)
1880 {
1881 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
1882 goto fail;
1883 }
1884
1885 priv->isOpened = FALSE;
1886 priv->isReady = FALSE;
1887 priv->ownThread = TRUE;
1888
1889 {
1890 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1891 priv->activeCapSet = empty;
1892 }
1893
1894 return context;
1895fail:
1896 WINPR_PRAGMA_DIAG_PUSH
1897 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1898 rdpgfx_server_context_free(context);
1899 WINPR_PRAGMA_DIAG_POP
1900 return nullptr;
1901}
1902
1903void rdpgfx_server_context_free(RdpgfxServerContext* context)
1904{
1905 if (!context)
1906 return;
1907
1908 (void)rdpgfx_server_close(context);
1909
1910 if (context->priv)
1911 Stream_Free(context->priv->input_stream, TRUE);
1912
1913 free(context->priv);
1914 free(context);
1915}
1916
1917HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context)
1918{
1919 if (!context)
1920 return nullptr;
1921 if (!context->priv)
1922 return nullptr;
1923 return context->priv->channelEvent;
1924}
1925
1926/*
1927 * Handle rpdgfx messages - server side
1928 *
1929 * @param context side context
1930 *
1931 * @return 0 on success
1932 * ERROR_NO_DATA if no data could be read this time
1933 * otherwise a Win32 error code
1934 */
1935UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
1936{
1937 DWORD BytesReturned = 0;
1938 void* buffer = nullptr;
1939 UINT ret = CHANNEL_RC_OK;
1940
1941 WINPR_ASSERT(context);
1942 WINPR_ASSERT(context->priv);
1943
1944 RdpgfxServerPrivate* priv = context->priv;
1945 wStream* s = priv->input_stream;
1946
1947 /* Check whether the dynamic channel is ready */
1948 if (!priv->isReady)
1949 {
1950 if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer,
1951 &BytesReturned) == FALSE)
1952 {
1953 if (GetLastError() == ERROR_NO_DATA)
1954 return ERROR_NO_DATA;
1955
1956 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
1957 return ERROR_INTERNAL_ERROR;
1958 }
1959
1960 priv->isReady = *((BOOL*)buffer);
1961 WTSFreeMemory(buffer);
1962 }
1963
1964 /* Consume channel event only after the gfx dynamic channel is ready */
1965 if (priv->isReady)
1966 {
1967 Stream_ResetPosition(s);
1968
1969 if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, nullptr, 0, &BytesReturned))
1970 {
1971 if (GetLastError() == ERROR_NO_DATA)
1972 return ERROR_NO_DATA;
1973
1974 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
1975 return ERROR_INTERNAL_ERROR;
1976 }
1977
1978 if (BytesReturned < 1)
1979 return CHANNEL_RC_OK;
1980
1981 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
1982 {
1983 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
1984 return CHANNEL_RC_NO_MEMORY;
1985 }
1986
1987 const size_t len = Stream_Capacity(s);
1988 if (len > UINT32_MAX)
1989 return ERROR_INTERNAL_ERROR;
1990 if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, Stream_BufferAs(s, char), (UINT32)len,
1991 &BytesReturned) == FALSE)
1992 {
1993 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
1994 return ERROR_INTERNAL_ERROR;
1995 }
1996
1997 if (!Stream_SetLength(s, BytesReturned))
1998 return ERROR_INTERNAL_ERROR;
1999
2000 Stream_ResetPosition(s);
2001
2002 while (Stream_GetPosition(s) < Stream_Length(s))
2003 {
2004 if ((ret = rdpgfx_server_receive_pdu(context, s)))
2005 {
2006 WLog_Print(context->priv->log, WLOG_ERROR,
2007 "rdpgfx_server_receive_pdu "
2008 "failed with error %" PRIu32 "!",
2009 ret);
2010 return ret;
2011 }
2012 }
2013 }
2014
2015 return ret;
2016}