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 switch (cmd->codecId)
782 {
783#if defined(WITH_GFX_AV1)
784 case RDPGFX_CODECID_AV1:
785#endif
786 case RDPGFX_CODECID_AVC420:
787 {
788 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
789 error = rdpgfx_write_h264_avc420(log, s, havc420);
790
791 if (error != CHANNEL_RC_OK)
792 {
793 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
794 return error;
795 }
796 }
797 break;
798
799 case RDPGFX_CODECID_AVC444:
800 case RDPGFX_CODECID_AVC444v2:
801 {
802 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
803 havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */
804 if (!Stream_EnsureRemainingCapacity(s, 4))
805 return ERROR_INTERNAL_ERROR;
806 Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 |
807 ((uint32_t)havc444->LC << 30UL));
808 /* avc420EncodedBitstream1 */
809 error = rdpgfx_write_h264_avc420(log, s, havc420);
810
811 if (error != CHANNEL_RC_OK)
812 {
813 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
814 return error;
815 }
816
817 /* avc420EncodedBitstream2 */
818 if (havc444->LC == 0)
819 {
820 havc420 = &(havc444->bitstream[1]);
821 error = rdpgfx_write_h264_avc420(log, s, havc420);
822
823 if (error != CHANNEL_RC_OK)
824 {
825 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
826 return error;
827 }
828 }
829 }
830 break;
831 default:
832 if (!Stream_EnsureRemainingCapacity(s, cmd->length))
833 return ERROR_INTERNAL_ERROR;
834 Stream_Write(s, cmd->data, cmd->length);
835 break;
836 }
837
838 /* Fill actual bitmap data length */
839 const size_t bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart;
840 if (bitmapDataLength > UINT32_MAX)
841 return ERROR_INTERNAL_ERROR;
842
843 if (!Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32)))
844 return ERROR_INVALID_DATA;
845 if (!Stream_EnsureRemainingCapacity(s, 4))
846 return ERROR_INTERNAL_ERROR;
847 Stream_Write_UINT32(s, (UINT32)bitmapDataLength); /* bitmapDataLength (4 bytes) */
848 if (!Stream_SafeSeek(s, bitmapDataLength))
849 return ERROR_INTERNAL_ERROR;
850 }
851
852 return error;
853}
854
862WINPR_ATTR_NODISCARD static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context,
863 const RDPGFX_SURFACE_COMMAND* cmd)
864{
865 if (!checkCapsAreExchanged(context))
866 return CHANNEL_RC_NOT_INITIALIZED;
867 UINT error = CHANNEL_RC_OK;
868
869 WINPR_ASSERT(context);
870 WINPR_ASSERT(context->priv);
871 WINPR_ASSERT(cmd);
872
873 wStream* s =
874 rdpgfx_server_single_packet_new(context->priv->log, rdpgfx_surface_command_cmdid(cmd),
875 rdpgfx_estimate_surface_command(cmd));
876
877 if (!s)
878 {
879 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
880 return CHANNEL_RC_NO_MEMORY;
881 }
882
883 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
884
885 if (error != CHANNEL_RC_OK)
886 {
887 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
888 goto error;
889 }
890
891 return rdpgfx_server_single_packet_send(context, s);
892error:
893 Stream_Free(s, TRUE);
894 return error;
895}
896
905WINPR_ATTR_NODISCARD static UINT
906rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, const RDPGFX_SURFACE_COMMAND* cmd,
907 const RDPGFX_START_FRAME_PDU* startFrame,
908 const RDPGFX_END_FRAME_PDU* endFrame)
909
910{
911 if (!checkCapsAreExchanged(context))
912 return CHANNEL_RC_NOT_INITIALIZED;
913
914 WINPR_ASSERT(context->priv);
915 WINPR_ASSERT(cmd);
916 WINPR_ASSERT(startFrame);
917 WINPR_ASSERT(endFrame);
918
919 UINT error = CHANNEL_RC_OK;
920 size_t size = rdpgfx_pdu_length(rdpgfx_estimate_surface_command(cmd));
921
922 if (startFrame)
923 {
924 size += rdpgfx_pdu_length(RDPGFX_START_FRAME_PDU_SIZE);
925 }
926
927 if (endFrame)
928 {
929 size += rdpgfx_pdu_length(RDPGFX_END_FRAME_PDU_SIZE);
930 }
931
932 wStream* s = Stream_New(nullptr, size);
933
934 if (!s)
935 {
936 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
937 return CHANNEL_RC_NO_MEMORY;
938 }
939
940 /* Write start frame if exists */
941 if (startFrame)
942 {
943 const size_t position = Stream_GetPosition(s);
944 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_STARTFRAME, 0);
945
946 if (error != CHANNEL_RC_OK)
947 {
948 WLog_Print(context->priv->log, WLOG_ERROR,
949 "Failed to init header with error %" PRIu32 "!", error);
950 goto error;
951 }
952
953 if (!rdpgfx_write_start_frame_pdu(s, startFrame) ||
954 !rdpgfx_server_packet_complete_header(s, position))
955 {
956 error = ERROR_INTERNAL_ERROR;
957 goto error;
958 }
959 }
960
961 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */
962 {
963 const size_t pos = Stream_GetPosition(s);
964 error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd),
965 0); // Actual length will be filled later
966
967 if (error != CHANNEL_RC_OK)
968 {
969 WLog_Print(context->priv->log, WLOG_ERROR,
970 "Failed to init header with error %" PRIu32 "!", error);
971 goto error;
972 }
973
974 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
975
976 if (error != CHANNEL_RC_OK)
977 {
978 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
979 goto error;
980 }
981
982 if (!rdpgfx_server_packet_complete_header(s, pos))
983 {
984 error = ERROR_INTERNAL_ERROR;
985 goto error;
986 }
987 }
988
989 /* Write end frame if exists */
990 if (endFrame)
991 {
992 const size_t position = Stream_GetPosition(s);
993 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0);
994
995 if (error != CHANNEL_RC_OK)
996 {
997 WLog_Print(context->priv->log, WLOG_ERROR,
998 "Failed to init header with error %" PRIu32 "!", error);
999 goto error;
1000 }
1001
1002 if (!rdpgfx_write_end_frame_pdu(s, endFrame) ||
1003 !rdpgfx_server_packet_complete_header(s, position))
1004 {
1005 error = ERROR_INTERNAL_ERROR;
1006 goto error;
1007 }
1008 }
1009
1010 return rdpgfx_server_packet_send(context, s);
1011error:
1012 Stream_Free(s, TRUE);
1013 return error;
1014}
1015
1021WINPR_ATTR_NODISCARD static UINT
1022rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context,
1024{
1025 if (!checkCapsAreExchanged(context))
1026 return CHANNEL_RC_NOT_INITIALIZED;
1027
1028 WINPR_ASSERT(context->priv);
1029 WINPR_ASSERT(pdu);
1030 wStream* s =
1031 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6);
1032
1033 if (!s)
1034 {
1035 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1036 return CHANNEL_RC_NO_MEMORY;
1037 }
1038
1039 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1040 Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */
1041 return rdpgfx_server_single_packet_send(context, s);
1042}
1043
1049WINPR_ATTR_NODISCARD static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context,
1050 const RDPGFX_SOLID_FILL_PDU* pdu)
1051{
1052 if (!checkCapsAreExchanged(context))
1053 return CHANNEL_RC_NOT_INITIALIZED;
1054
1055 WINPR_ASSERT(context->priv);
1056 WINPR_ASSERT(pdu);
1057
1058 UINT error = CHANNEL_RC_OK;
1059 RECTANGLE_16* fillRect = nullptr;
1060 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SOLIDFILL,
1061 8 + 8 * pdu->fillRectCount);
1062
1063 if (!s)
1064 {
1065 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1066 return CHANNEL_RC_NO_MEMORY;
1067 }
1068
1069 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1070
1071 /* fillPixel (4 bytes) */
1072 if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel))))
1073 {
1074 WLog_Print(context->priv->log, WLOG_ERROR,
1075 "rdpgfx_write_color32 failed with error %" PRIu32 "!", error);
1076 goto error;
1077 }
1078
1079 Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */
1080
1081 for (UINT16 index = 0; index < pdu->fillRectCount; index++)
1082 {
1083 fillRect = &(pdu->fillRects[index]);
1084
1085 if ((error = rdpgfx_write_rect16(s, fillRect)))
1086 {
1087 WLog_Print(context->priv->log, WLOG_ERROR,
1088 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1089 goto error;
1090 }
1091 }
1092
1093 return rdpgfx_server_single_packet_send(context, s);
1094error:
1095 Stream_Free(s, TRUE);
1096 return error;
1097}
1098
1104WINPR_ATTR_NODISCARD static UINT
1105rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context,
1107{
1108 if (!checkCapsAreExchanged(context))
1109 return CHANNEL_RC_NOT_INITIALIZED;
1110
1111 WINPR_ASSERT(pdu);
1112 WINPR_ASSERT(context->priv);
1113
1114 UINT error = CHANNEL_RC_OK;
1115 RDPGFX_POINT16* destPt = nullptr;
1116 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOSURFACE,
1117 14 + 4 * pdu->destPtsCount);
1118
1119 if (!s)
1120 {
1121 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1122 return CHANNEL_RC_NO_MEMORY;
1123 }
1124
1125 Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
1126 Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */
1127
1128 /* rectSrc (8 bytes ) */
1129 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1130 {
1131 WLog_Print(context->priv->log, WLOG_ERROR,
1132 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1133 goto error;
1134 }
1135
1136 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1137
1138 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1139 {
1140 destPt = &(pdu->destPts[index]);
1141
1142 if ((error = rdpgfx_write_point16(s, destPt)))
1143 {
1144 WLog_Print(context->priv->log, WLOG_ERROR,
1145 "rdpgfx_write_point16 failed with error %" PRIu32 "!", error);
1146 goto error;
1147 }
1148 }
1149
1150 return rdpgfx_server_single_packet_send(context, s);
1151error:
1152 Stream_Free(s, TRUE);
1153 return error;
1154}
1155
1161WINPR_ATTR_NODISCARD static UINT
1162rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context,
1163 const RDPGFX_SURFACE_TO_CACHE_PDU* pdu)
1164{
1165 if (!checkCapsAreExchanged(context))
1166 return CHANNEL_RC_NOT_INITIALIZED;
1167
1168 WINPR_ASSERT(pdu);
1169 WINPR_ASSERT(context->priv);
1170
1171 UINT error = CHANNEL_RC_OK;
1172 wStream* s =
1173 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOCACHE, 20);
1174
1175 if (!s)
1176 {
1177 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1178 return CHANNEL_RC_NO_MEMORY;
1179 }
1180
1181 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1182 Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */
1183 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1184
1185 /* rectSrc (8 bytes ) */
1186 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1187 {
1188 WLog_Print(context->priv->log, WLOG_ERROR,
1189 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1190 goto error;
1191 }
1192
1193 return rdpgfx_server_single_packet_send(context, s);
1194error:
1195 Stream_Free(s, TRUE);
1196 return error;
1197}
1198
1204WINPR_ATTR_NODISCARD static UINT
1205rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context,
1206 const RDPGFX_CACHE_TO_SURFACE_PDU* pdu)
1207{
1208 if (!checkCapsAreExchanged(context))
1209 return CHANNEL_RC_NOT_INITIALIZED;
1210
1211 WINPR_ASSERT(pdu);
1212 WINPR_ASSERT(context->priv);
1213
1214 UINT error = CHANNEL_RC_OK;
1215 RDPGFX_POINT16* destPt = nullptr;
1216 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHETOSURFACE,
1217 6 + 4 * pdu->destPtsCount);
1218
1219 if (!s)
1220 {
1221 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1222 return CHANNEL_RC_NO_MEMORY;
1223 }
1224
1225 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1226 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1227 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1228
1229 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1230 {
1231 destPt = &(pdu->destPts[index]);
1232
1233 if ((error = rdpgfx_write_point16(s, destPt)))
1234 {
1235 WLog_Print(context->priv->log, WLOG_ERROR,
1236 "rdpgfx_write_point16 failed with error %" PRIu32 "", error);
1237 goto error;
1238 }
1239 }
1240
1241 return rdpgfx_server_single_packet_send(context, s);
1242error:
1243 Stream_Free(s, TRUE);
1244 return error;
1245}
1246
1252WINPR_ATTR_NODISCARD static UINT
1253rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context,
1255{
1256 if (!checkCapsAreExchanged(context))
1257 return CHANNEL_RC_NOT_INITIALIZED;
1258
1259 WINPR_ASSERT(pdu);
1260 WINPR_ASSERT(context->priv);
1261 wStream* s =
1262 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12);
1263
1264 if (!s)
1265 {
1266 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1267 return CHANNEL_RC_NO_MEMORY;
1268 }
1269
1270 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1271 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1272 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1273 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1274 return rdpgfx_server_single_packet_send(context, s);
1275}
1276
1282WINPR_ATTR_NODISCARD static UINT
1283rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context,
1285{
1286 if (!checkCapsAreExchanged(context))
1287 return CHANNEL_RC_NOT_INITIALIZED;
1288
1289 WINPR_ASSERT(pdu);
1290 WINPR_ASSERT(context->priv);
1291
1292 wStream* s =
1293 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOWINDOW, 18);
1294
1295 if (!s)
1296 {
1297 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1298 return CHANNEL_RC_NO_MEMORY;
1299 }
1300
1301 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1302 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1303 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1304 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1305 return rdpgfx_server_single_packet_send(context, s);
1306}
1307
1308WINPR_ATTR_NODISCARD static UINT
1309rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context,
1311{
1312 if (!checkCapsAreExchanged(context))
1313 return CHANNEL_RC_NOT_INITIALIZED;
1314
1315 WINPR_ASSERT(pdu);
1316 WINPR_ASSERT(context->priv);
1317 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1318 RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26);
1319
1320 if (!s)
1321 {
1322 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1323 return CHANNEL_RC_NO_MEMORY;
1324 }
1325
1326 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1327 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1328 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1329 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1330 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1331 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1332 return rdpgfx_server_single_packet_send(context, s);
1333}
1334
1340WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context,
1341 wStream* s)
1342{
1343 WINPR_ASSERT(context);
1344
1345 if (!checkCapsAreExchanged(context))
1346 return CHANNEL_RC_NOT_INITIALIZED;
1347
1348 WINPR_ASSERT(context->priv);
1349
1350 RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu = WINPR_C_ARRAY_INIT;
1351 UINT error = CHANNEL_RC_OK;
1352
1353 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1354 return ERROR_INVALID_DATA;
1355
1356 Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */
1357 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1358 Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
1359
1360 IFCALLRET(context->FrameAcknowledge, error, context, &pdu);
1361
1362 if (error)
1363 WLog_Print(context->priv->log, WLOG_ERROR,
1364 "context->FrameAcknowledge failed with error %" PRIu32 "", error);
1365
1366 return error;
1367}
1368
1374WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context,
1375 wStream* s)
1376{
1377 WINPR_ASSERT(context);
1378 if (!checkCapsAreExchanged(context))
1379 return CHANNEL_RC_NOT_INITIALIZED;
1380
1381 WINPR_ASSERT(context->priv);
1382
1383 RDPGFX_CACHE_IMPORT_OFFER_PDU pdu = WINPR_C_ARRAY_INIT;
1384 RDPGFX_CACHE_ENTRY_METADATA* cacheEntry = nullptr;
1385 UINT error = CHANNEL_RC_OK;
1386
1387 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1388 return ERROR_INVALID_DATA;
1389
1390 /* cacheEntriesCount (2 bytes) */
1391 Stream_Read_UINT16(s, pdu.cacheEntriesCount);
1392
1393 /* 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU */
1394 if (pdu.cacheEntriesCount >= 5462)
1395 {
1396 WLog_Print(context->priv->log, WLOG_ERROR, "Invalid cacheEntriesCount: %" PRIu16 "",
1397 pdu.cacheEntriesCount);
1398 return ERROR_INVALID_DATA;
1399 }
1400
1401 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(context->priv->log, s, pdu.cacheEntriesCount,
1402 12ull))
1403 return ERROR_INVALID_DATA;
1404
1405 for (UINT16 index = 0; index < pdu.cacheEntriesCount; index++)
1406 {
1407 cacheEntry = &(pdu.cacheEntries[index]);
1408 Stream_Read_UINT64(s, cacheEntry->cacheKey); /* cacheKey (8 bytes) */
1409 Stream_Read_UINT32(s, cacheEntry->bitmapLength); /* bitmapLength (4 bytes) */
1410 }
1411
1412 IFCALLRET(context->CacheImportOffer, error, context, &pdu);
1413
1414 if (error)
1415 WLog_Print(context->priv->log, WLOG_ERROR,
1416 "context->CacheImportOffer failed with error %" PRIu32 "", error);
1417
1418 return error;
1419}
1420
1426WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context,
1427 wStream* s)
1428{
1429 RDPGFX_CAPSET* capsSets = nullptr;
1430 RDPGFX_CAPS_ADVERTISE_PDU pdu = WINPR_C_ARRAY_INIT;
1431 UINT error = ERROR_INVALID_DATA;
1432
1433 if (!context)
1434 return ERROR_BAD_ARGUMENTS;
1435
1436 WINPR_ASSERT(context->priv);
1437 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1438 return ERROR_INVALID_DATA;
1439
1440 Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
1441 if (pdu.capsSetCount > 0)
1442 {
1443 capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4));
1444 if (!capsSets)
1445 return ERROR_OUTOFMEMORY;
1446 }
1447
1448 pdu.capsSets = capsSets;
1449
1450 for (UINT16 index = 0; index < pdu.capsSetCount; index++)
1451 {
1452 RDPGFX_CAPSET* capsSet = &(pdu.capsSets[index]);
1453
1454 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
1455 goto fail;
1456
1457 Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */
1458 Stream_Read_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
1459
1460 if (capsSet->length >= 4)
1461 {
1462 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1463 goto fail;
1464
1465 Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
1466 }
1467
1468 if (!Stream_SafeSeek(s, capsSet->length))
1469 goto fail;
1470 }
1471
1472 error = ERROR_BAD_CONFIGURATION;
1473 IFCALLRET(context->CapsAdvertise, error, context, &pdu);
1474
1475 if (error)
1476 WLog_Print(context->priv->log, WLOG_ERROR,
1477 "context->CapsAdvertise failed with error %" PRIu32 "", error);
1478
1479fail:
1480 free(capsSets);
1481 return error;
1482}
1483
1489WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context,
1490 wStream* s)
1491{
1492 WINPR_ASSERT(context);
1493
1494 if (!checkCapsAreExchanged(context))
1495 return CHANNEL_RC_NOT_INITIALIZED;
1496
1497 RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu = WINPR_C_ARRAY_INIT;
1498 UINT error = CHANNEL_RC_OK;
1499
1500 WINPR_ASSERT(context->priv);
1501
1502 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1503 return ERROR_INVALID_DATA;
1504
1505 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1506 Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
1507 Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */
1508 Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */
1509
1510 IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu);
1511
1512 if (error)
1513 WLog_Print(context->priv->log, WLOG_ERROR,
1514 "context->QoeFrameAcknowledge failed with error %" PRIu32 "", error);
1515
1516 return error;
1517}
1518
1519WINPR_ATTR_NODISCARD static UINT
1520rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context,
1522{
1523 if (!checkCapsAreExchanged(context))
1524 return CHANNEL_RC_NOT_INITIALIZED;
1525
1526 WINPR_ASSERT(pdu);
1527 WINPR_ASSERT(context->priv);
1528 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1529 RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20);
1530
1531 if (!s)
1532 {
1533 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1534 return CHANNEL_RC_NO_MEMORY;
1535 }
1536
1537 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1538 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1539 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1540 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1541 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1542 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1543 return rdpgfx_server_single_packet_send(context, s);
1544}
1545
1551WINPR_ATTR_NODISCARD static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
1552{
1553 size_t end = 0;
1554 RDPGFX_HEADER header = WINPR_C_ARRAY_INIT;
1555 UINT error = CHANNEL_RC_OK;
1556 size_t beg = Stream_GetPosition(s);
1557
1558 WINPR_ASSERT(context);
1559 WINPR_ASSERT(context->priv);
1560
1561 if ((error = rdpgfx_read_header(context->priv->log, s, &header, nullptr)))
1562 {
1563 WLog_Print(context->priv->log, WLOG_ERROR,
1564 "rdpgfx_read_header failed with error %" PRIu32 "!", error);
1565 return error;
1566 }
1567
1568 WLog_Print(context->priv->log, WLOG_TRACE,
1569 "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "",
1570 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
1571 header.pduLength);
1572
1573 switch (header.cmdId)
1574 {
1575 case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
1576 if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
1577 WLog_Print(context->priv->log, WLOG_ERROR,
1578 "rdpgfx_recv_frame_acknowledge_pdu "
1579 "failed with error %" PRIu32 "!",
1580 error);
1581
1582 break;
1583
1584 case RDPGFX_CMDID_CACHEIMPORTOFFER:
1585 if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
1586 WLog_Print(context->priv->log, WLOG_ERROR,
1587 "rdpgfx_recv_cache_import_offer_pdu "
1588 "failed with error %" PRIu32 "!",
1589 error);
1590
1591 break;
1592
1593 case RDPGFX_CMDID_CAPSADVERTISE:
1594 if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
1595 WLog_Print(context->priv->log, WLOG_ERROR,
1596 "rdpgfx_recv_caps_advertise_pdu "
1597 "failed with error %" PRIu32 "!",
1598 error);
1599
1600 break;
1601
1602 case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
1603 if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
1604 WLog_Print(context->priv->log, WLOG_ERROR,
1605 "rdpgfx_recv_qoe_frame_acknowledge_pdu "
1606 "failed with error %" PRIu32 "!",
1607 error);
1608
1609 break;
1610
1611 default:
1612 error = CHANNEL_RC_BAD_PROC;
1613 break;
1614 }
1615
1616 if (error)
1617 {
1618 WLog_Print(context->priv->log, WLOG_ERROR,
1619 "Error while parsing GFX cmdId: %s (0x%04" PRIX16 ")",
1620 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
1621 return error;
1622 }
1623
1624 end = Stream_GetPosition(s);
1625
1626 if (end != (beg + header.pduLength))
1627 {
1628 WLog_Print(context->priv->log, WLOG_ERROR,
1629 "Unexpected gfx pdu end: Actual: %" PRIuz ", Expected: %" PRIuz "", end,
1630 (beg + header.pduLength));
1631 if (!Stream_SetPosition(s, (beg + header.pduLength)))
1632 return ERROR_INVALID_DATA;
1633 }
1634
1635 return error;
1636}
1637
1638WINPR_ATTR_NODISCARD static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
1639{
1640 RdpgfxServerContext* context = (RdpgfxServerContext*)arg;
1641 WINPR_ASSERT(context);
1642
1643 RdpgfxServerPrivate* priv = context->priv;
1644 DWORD status = 0;
1645 DWORD nCount = 0;
1646 HANDLE events[8] = WINPR_C_ARRAY_INIT;
1647 UINT error = CHANNEL_RC_OK;
1648
1649 WINPR_ASSERT(priv);
1650
1651 if (priv->ownThread)
1652 {
1653 WINPR_ASSERT(priv->stopEvent);
1654 events[nCount++] = priv->stopEvent;
1655 }
1656
1657 WINPR_ASSERT(priv->channelEvent);
1658 events[nCount++] = priv->channelEvent;
1659
1660 /* Main virtual channel loop. RDPGFX do not need version negotiation */
1661 while (TRUE)
1662 {
1663 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1664
1665 if (status == WAIT_FAILED)
1666 {
1667 error = GetLastError();
1668 WLog_Print(context->priv->log, WLOG_ERROR,
1669 "WaitForMultipleObjects failed with error %" PRIu32 "", error);
1670 break;
1671 }
1672
1673 /* Stop Event */
1674 if (status == WAIT_OBJECT_0)
1675 break;
1676
1677 if ((error = rdpgfx_server_handle_messages(context)))
1678 {
1679 WLog_Print(context->priv->log, WLOG_ERROR,
1680 "rdpgfx_server_handle_messages failed with error %" PRIu32 "", error);
1681 break;
1682 }
1683 }
1684
1685 if (error && context->rdpcontext)
1686 setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error");
1687
1688 ExitThread(error);
1689 return error;
1690}
1691
1692WINPR_ATTR_NODISCARD static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
1693{
1694 WINPR_ASSERT(context);
1695 RdpgfxServerPrivate* priv = context->priv;
1696 void* buffer = nullptr;
1697
1698 WINPR_ASSERT(priv);
1699
1700 if (!priv->isOpened)
1701 {
1702 PULONG pSessionId = nullptr;
1703 DWORD BytesReturned = 0;
1704 priv->SessionId = WTS_CURRENT_SESSION;
1705 UINT32 channelId = 0;
1706 BOOL status = TRUE;
1707
1708 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
1709 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
1710 {
1711 WLog_Print(context->priv->log, WLOG_ERROR, "WTSQuerySessionInformationA failed!");
1712 return FALSE;
1713 }
1714
1715 priv->SessionId = (DWORD)*pSessionId;
1716 WTSFreeMemory(pSessionId);
1717 priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME,
1718 WTS_CHANNEL_OPTION_DYNAMIC);
1719
1720 if (!priv->rdpgfx_channel)
1721 {
1722 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelOpenEx failed!");
1723 return FALSE;
1724 }
1725
1726 channelId = WTSChannelGetIdByHandle(priv->rdpgfx_channel);
1727
1728 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
1729 if (!status)
1730 {
1731 WLog_Print(context->priv->log, WLOG_ERROR, "context->ChannelIdAssigned failed!");
1732 goto fail;
1733 }
1734
1735 /* Query for channel event handle */
1736 if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
1737 &BytesReturned) ||
1738 (BytesReturned != sizeof(HANDLE)))
1739 {
1740 WLog_Print(context->priv->log, WLOG_ERROR,
1741 "WTSVirtualChannelQuery failed "
1742 "or invalid returned size(%" PRIu32 ")",
1743 BytesReturned);
1744
1745 if (buffer)
1746 WTSFreeMemory(buffer);
1747
1748 goto fail;
1749 }
1750
1751 priv->channelEvent = *(HANDLE*)buffer;
1752 WTSFreeMemory(buffer);
1753
1754 if (!(priv->zgfx = zgfx_context_new(TRUE)))
1755 {
1756 WLog_Print(context->priv->log, WLOG_ERROR, "Create zgfx context failed!");
1757 goto fail;
1758 }
1759
1760 priv->isReady = FALSE;
1761 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1762 priv->activeCapSet = empty;
1763 if (priv->ownThread)
1764 {
1765 if (!(priv->stopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
1766 {
1767 WLog_Print(context->priv->log, WLOG_ERROR, "CreateEvent failed!");
1768 goto fail;
1769 }
1770
1771 if (!(priv->thread = CreateThread(nullptr, 0, rdpgfx_server_thread_func, (void*)context,
1772 0, nullptr)))
1773 {
1774 WLog_Print(context->priv->log, WLOG_ERROR, "CreateThread failed!");
1775 goto fail;
1776 }
1777 }
1778
1779 priv->isOpened = TRUE;
1780 return TRUE;
1781 }
1782
1783 WLog_Print(context->priv->log, WLOG_ERROR, "RDPGFX channel is already opened!");
1784 return FALSE;
1785fail:
1786 (void)rdpgfx_server_close(context);
1787 return FALSE;
1788}
1789
1790BOOL rdpgfx_server_close(RdpgfxServerContext* context)
1791{
1792 WINPR_ASSERT(context);
1793
1794 RdpgfxServerPrivate* priv = context->priv;
1795 WINPR_ASSERT(priv);
1796
1797 if (priv->ownThread && priv->thread)
1798 {
1799 (void)SetEvent(priv->stopEvent);
1800
1801 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
1802 {
1803 WLog_Print(context->priv->log, WLOG_ERROR,
1804 "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
1805 return FALSE;
1806 }
1807
1808 (void)CloseHandle(priv->thread);
1809 (void)CloseHandle(priv->stopEvent);
1810 priv->thread = nullptr;
1811 priv->stopEvent = nullptr;
1812 }
1813
1814 zgfx_context_free(priv->zgfx);
1815 priv->zgfx = nullptr;
1816
1817 if (priv->rdpgfx_channel)
1818 {
1819 (void)WTSVirtualChannelClose(priv->rdpgfx_channel);
1820 priv->rdpgfx_channel = nullptr;
1821 }
1822
1823 priv->channelEvent = nullptr;
1824 priv->isOpened = FALSE;
1825 priv->isReady = FALSE;
1826 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1827 priv->activeCapSet = empty;
1828 return TRUE;
1829}
1830
1831WINPR_ATTR_NODISCARD static BOOL rdpgfx_server_initialize(RdpgfxServerContext* context,
1832 BOOL externalThread)
1833{
1834 WINPR_ASSERT(context);
1835 WINPR_ASSERT(context->priv);
1836
1837 if (context->priv->isOpened)
1838 {
1839 WLog_Print(context->priv->log, WLOG_WARN,
1840 "Application error: RDPEGFX channel already initialized, "
1841 "calling in this state is not possible!");
1842 return FALSE;
1843 }
1844
1845 context->priv->ownThread = !externalThread;
1846 return TRUE;
1847}
1848
1849RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm)
1850{
1851 RdpgfxServerContext* context = (RdpgfxServerContext*)calloc(1, sizeof(RdpgfxServerContext));
1852
1853 if (!context)
1854 return nullptr;
1855
1856 context->vcm = vcm;
1857 context->Initialize = rdpgfx_server_initialize;
1858 context->Open = rdpgfx_server_open;
1859 context->Close = rdpgfx_server_close;
1860 context->ResetGraphics = rdpgfx_send_reset_graphics_pdu;
1861 context->StartFrame = rdpgfx_send_start_frame_pdu;
1862 context->EndFrame = rdpgfx_send_end_frame_pdu;
1863 context->SurfaceCommand = rdpgfx_send_surface_command;
1864 context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command;
1865 context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu;
1866 context->CreateSurface = rdpgfx_send_create_surface_pdu;
1867 context->DeleteSurface = rdpgfx_send_delete_surface_pdu;
1868 context->SolidFill = rdpgfx_send_solid_fill_pdu;
1869 context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu;
1870 context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu;
1871 context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu;
1872 context->CacheImportOffer = rdpgfx_process_cache_import_offer_pdu;
1873 context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu;
1874 context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu;
1875 context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu;
1876 context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu;
1877 context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu;
1878 context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu;
1879 context->CapsAdvertise = nullptr;
1880 context->CapsConfirm = rdpgfx_send_caps_confirm_pdu;
1881 context->FrameAcknowledge = nullptr;
1882 context->QoeFrameAcknowledge = nullptr;
1883 RdpgfxServerPrivate* priv = context->priv =
1884 (RdpgfxServerPrivate*)calloc(1, sizeof(RdpgfxServerPrivate));
1885
1886 if (!priv)
1887 goto fail;
1888
1889 priv->log = WLog_Get(TAG);
1890 if (!priv->log)
1891 goto fail;
1892
1893 /* Create shared input stream */
1894 priv->input_stream = Stream_New(nullptr, 4);
1895
1896 if (!priv->input_stream)
1897 {
1898 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
1899 goto fail;
1900 }
1901
1902 priv->isOpened = FALSE;
1903 priv->isReady = FALSE;
1904 priv->ownThread = TRUE;
1905
1906 {
1907 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1908 priv->activeCapSet = empty;
1909 }
1910
1911 return context;
1912fail:
1913 WINPR_PRAGMA_DIAG_PUSH
1914 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1915 rdpgfx_server_context_free(context);
1916 WINPR_PRAGMA_DIAG_POP
1917 return nullptr;
1918}
1919
1920void rdpgfx_server_context_free(RdpgfxServerContext* context)
1921{
1922 if (!context)
1923 return;
1924
1925 (void)rdpgfx_server_close(context);
1926
1927 if (context->priv)
1928 Stream_Free(context->priv->input_stream, TRUE);
1929
1930 free(context->priv);
1931 free(context);
1932}
1933
1934HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context)
1935{
1936 if (!context)
1937 return nullptr;
1938 if (!context->priv)
1939 return nullptr;
1940 return context->priv->channelEvent;
1941}
1942
1943/*
1944 * Handle rpdgfx messages - server side
1945 *
1946 * @param context side context
1947 *
1948 * @return 0 on success
1949 * ERROR_NO_DATA if no data could be read this time
1950 * otherwise a Win32 error code
1951 */
1952UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
1953{
1954 DWORD BytesReturned = 0;
1955 void* buffer = nullptr;
1956 UINT ret = CHANNEL_RC_OK;
1957
1958 WINPR_ASSERT(context);
1959 WINPR_ASSERT(context->priv);
1960
1961 RdpgfxServerPrivate* priv = context->priv;
1962 wStream* s = priv->input_stream;
1963
1964 /* Check whether the dynamic channel is ready */
1965 if (!priv->isReady)
1966 {
1967 if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer,
1968 &BytesReturned) == FALSE)
1969 {
1970 if (GetLastError() == ERROR_NO_DATA)
1971 return ERROR_NO_DATA;
1972
1973 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
1974 return ERROR_INTERNAL_ERROR;
1975 }
1976
1977 priv->isReady = *((BOOL*)buffer);
1978 WTSFreeMemory(buffer);
1979 }
1980
1981 /* Consume channel event only after the gfx dynamic channel is ready */
1982 if (priv->isReady)
1983 {
1984 Stream_ResetPosition(s);
1985
1986 if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, nullptr, 0, &BytesReturned))
1987 {
1988 if (GetLastError() == ERROR_NO_DATA)
1989 return ERROR_NO_DATA;
1990
1991 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
1992 return ERROR_INTERNAL_ERROR;
1993 }
1994
1995 if (BytesReturned < 1)
1996 return CHANNEL_RC_OK;
1997
1998 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
1999 {
2000 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
2001 return CHANNEL_RC_NO_MEMORY;
2002 }
2003
2004 const size_t len = Stream_Capacity(s);
2005 if (len > UINT32_MAX)
2006 return ERROR_INTERNAL_ERROR;
2007 if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, Stream_BufferAs(s, char), (UINT32)len,
2008 &BytesReturned) == FALSE)
2009 {
2010 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
2011 return ERROR_INTERNAL_ERROR;
2012 }
2013
2014 if (!Stream_SetLength(s, BytesReturned))
2015 return ERROR_INTERNAL_ERROR;
2016
2017 Stream_ResetPosition(s);
2018
2019 while (Stream_GetPosition(s) < Stream_Length(s))
2020 {
2021 if ((ret = rdpgfx_server_receive_pdu(context, s)))
2022 {
2023 WLog_Print(context->priv->log, WLOG_ERROR,
2024 "rdpgfx_server_receive_pdu "
2025 "failed with error %" PRIu32 "!",
2026 ret);
2027 return ret;
2028 }
2029 }
2030 }
2031
2032 return ret;
2033}