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_SafeZero(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
577#if defined(WITH_GFX_AZURE)
578WINPR_ATTR_NODISCARD static inline UINT32
579rdpgfx_estimate_hevc(const RDPGFX_HEVC_BITMAP_STREAM* hevc)
580{
581 WINPR_ASSERT(hevc);
582 /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
583 UINT32 len = sizeof(UINT32) /* numRegionRects */
584 + 10ULL /* regionRects + quantQualityVals */
585 * hevc->meta.numRegionRects +
586 sizeof(UINT32) + /* cbNalSizes */
587 hevc->cbNalSizes + hevc->length;
588 if (hevc->frameAttributes >= 0)
589 len++;
590 return len;
591}
592#endif
593
600WINPR_ATTR_NODISCARD static inline UINT32
601rdpgfx_estimate_surface_command(const RDPGFX_SURFACE_COMMAND* cmd)
602{
603 RDPGFX_AVC420_BITMAP_STREAM* havc420 = nullptr;
604 RDPGFX_AVC444_BITMAP_STREAM* havc444 = nullptr;
605 UINT32 h264Size = 0;
606
607 WINPR_ASSERT(cmd);
608
609 /* Estimate stream size according to codec. */
610 switch (cmd->codecId)
611 {
612 case RDPGFX_CODECID_CAPROGRESSIVE:
613 case RDPGFX_CODECID_CAPROGRESSIVE_V2:
614 return RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE + cmd->length;
615
616#if defined(WITH_GFX_AZURE)
617 case RDPGFX_CODECID_HEVC420:
618 case RDPGFX_CODECID_HEVC444:
619 {
620 const RDPGFX_HEVC_BITMAP_STREAM* hevc = (const RDPGFX_HEVC_BITMAP_STREAM*)cmd->extra;
621 const UINT32 hevcSize = rdpgfx_estimate_hevc(hevc);
622 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + hevcSize;
623 }
624#endif
625
626#if defined(WITH_GFX_AV1) || defined(WITH_GFX_AV2)
627 case RDPGFX_CODECID_AV1:
628#endif
629 case RDPGFX_CODECID_AVC420:
630 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
631 h264Size = rdpgfx_estimate_h264_avc420(havc420);
632 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
633
634 case RDPGFX_CODECID_AVC444:
635 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
636 h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */
637 /* avc420EncodedBitstream1 */
638 havc420 = &(havc444->bitstream[0]);
639 h264Size += rdpgfx_estimate_h264_avc420(havc420);
640
641 /* avc420EncodedBitstream2 */
642 if (havc444->LC == 0)
643 {
644 havc420 = &(havc444->bitstream[1]);
645 h264Size += rdpgfx_estimate_h264_avc420(havc420);
646 }
647
648 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
649
650 default:
651 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + cmd->length;
652 }
653}
654
662WINPR_ATTR_NODISCARD static inline UINT16
663rdpgfx_surface_command_cmdid(const RDPGFX_SURFACE_COMMAND* cmd)
664{
665 WINPR_ASSERT(cmd);
666
667 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
668 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
669 {
670 return RDPGFX_CMDID_WIRETOSURFACE_2;
671 }
672
673 return RDPGFX_CMDID_WIRETOSURFACE_1;
674}
675
681WINPR_ATTR_NODISCARD static UINT rdpgfx_write_h264_metablock(wLog* log, wStream* s,
682 const RDPGFX_H264_METABLOCK* meta)
683{
684 RECTANGLE_16* regionRect = nullptr;
685 RDPGFX_H264_QUANT_QUALITY* quantQualityVal = nullptr;
686 UINT error = CHANNEL_RC_OK;
687
688 WINPR_ASSERT(meta);
689 if (!Stream_EnsureRemainingCapacity(s, 4ull + meta->numRegionRects * 10ull))
690 return ERROR_OUTOFMEMORY;
691
692 Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
693
694 for (UINT32 index = 0; index < meta->numRegionRects; index++)
695 {
696 regionRect = &(meta->regionRects[index]);
697
698 if ((error = rdpgfx_write_rect16(s, regionRect)))
699 {
700 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_rect16 failed with error %" PRIu32 "!",
701 error);
702 return error;
703 }
704 }
705
706 for (UINT32 index = 0; index < meta->numRegionRects; index++)
707 {
708 quantQualityVal = &(meta->quantQualityVals[index]);
709 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(
710 uint8_t, quantQualityVal->qp | (quantQualityVal->r << 6) |
711 (quantQualityVal->p << 7))); /* qpVal (1 byte) */
712 /* qualityVal (1 byte) */
713 Stream_Write_UINT8(s, quantQualityVal->qualityVal);
714 }
715
716 return error;
717}
718
725WINPR_ATTR_NODISCARD static inline UINT
726rdpgfx_write_h264_avc420(wLog* log, wStream* s, const RDPGFX_AVC420_BITMAP_STREAM* havc420)
727{
728 WINPR_ASSERT(havc420);
729 const UINT error = rdpgfx_write_h264_metablock(log, s, &(havc420->meta));
730
731 if (error != CHANNEL_RC_OK)
732 {
733 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_metablock failed with error %" PRIu32 "!",
734 error);
735 return error;
736 }
737
738 if (!Stream_EnsureRemainingCapacity(s, havc420->length))
739 return ERROR_OUTOFMEMORY;
740
741 Stream_Write(s, havc420->data, havc420->length);
742 return error;
743}
744
745#if defined(WITH_GFX_AZURE)
746WINPR_ATTR_NODISCARD static inline UINT rdpgfx_write_hevc(wLog* log, wStream* s,
747 const RDPGFX_HEVC_BITMAP_STREAM* hevc)
748{
749 WINPR_ASSERT(hevc);
750 const UINT error = rdpgfx_write_h264_metablock(log, s, &(hevc->meta));
751
752 if (error != CHANNEL_RC_OK)
753 {
754 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_metablock failed with error %" PRIu32 "!",
755 error);
756 return error;
757 }
758
759 if (!Stream_EnsureRemainingCapacity(s, sizeof(UINT32)))
760 return ERROR_OUTOFMEMORY;
761 Stream_Write_UINT32(s, hevc->cbNalSizes);
762
763 if (!Stream_EnsureRemainingCapacity(s, hevc->cbNalSizes))
764 return ERROR_OUTOFMEMORY;
765
766 for (size_t x = 0; x < hevc->cbNalSizes / 4; x++)
767 Stream_Write_UINT32(s, hevc->nalSize[x]);
768
769 if (hevc->frameAttributes >= 0)
770 {
771 if (!Stream_EnsureRemainingCapacity(s, 1))
772 return ERROR_OUTOFMEMORY;
773
774 Stream_Write_UINT8(s, hevc->frameAttributes & 0xff);
775 }
776
777 if (!Stream_EnsureRemainingCapacity(s, hevc->length))
778 return ERROR_OUTOFMEMORY;
779
780 Stream_Write(s, hevc->data, hevc->length);
781 return error;
782}
783#endif
784
792WINPR_ATTR_NODISCARD static UINT rdpgfx_write_surface_command(wLog* log, wStream* s,
793 const RDPGFX_SURFACE_COMMAND* cmd)
794{
795 UINT error = CHANNEL_RC_OK;
796 RDPGFX_AVC420_BITMAP_STREAM* havc420 = nullptr;
797 RDPGFX_AVC444_BITMAP_STREAM* havc444 = nullptr;
798 UINT8 pixelFormat = 0;
799
800 WINPR_ASSERT(cmd);
801 switch (cmd->format)
802 {
803 case PIXEL_FORMAT_BGRX32:
804 pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
805 break;
806
807 case PIXEL_FORMAT_BGRA32:
808 pixelFormat = GFX_PIXEL_FORMAT_ARGB_8888;
809 break;
810
811 default:
812 WLog_Print(log, WLOG_ERROR, "Format %s not supported!",
813 FreeRDPGetColorFormatName(cmd->format));
814 return ERROR_INVALID_DATA;
815 }
816
817 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
818 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
819 {
820 if (!Stream_EnsureRemainingCapacity(s, 13ull + cmd->length))
821 return ERROR_INTERNAL_ERROR;
822 /* Write RDPGFX_CMDID_WIRETOSURFACE_2 format for CAPROGRESSIVE */
823 Stream_Write_UINT16(
824 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->surfaceId)); /* surfaceId (2 bytes) */
825 Stream_Write_UINT16(
826 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->codecId)); /* codecId (2 bytes) */
827 Stream_Write_UINT32(s, cmd->contextId); /* codecContextId (4 bytes) */
828 Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */
829 Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */
830 Stream_Write(s, cmd->data, cmd->length);
831 }
832 else
833 {
834 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 format for others */
835 if (!Stream_EnsureRemainingCapacity(s, 17))
836 return ERROR_INTERNAL_ERROR;
837 Stream_Write_UINT16(
838 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->surfaceId)); /* surfaceId (2 bytes) */
839 Stream_Write_UINT16(
840 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->codecId)); /* codecId (2 bytes) */
841 Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */
842 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->left)); /* left (2 bytes) */
843 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->top)); /* top (2 bytes) */
844 Stream_Write_UINT16(s,
845 WINPR_ASSERTING_INT_CAST(uint16_t, cmd->right)); /* right (2 bytes) */
846 Stream_Write_UINT16(s,
847 WINPR_ASSERTING_INT_CAST(uint16_t, cmd->bottom)); /* bottom (2 bytes) */
848 Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */
849 const size_t bitmapDataStart = Stream_GetPosition(s);
850
851 switch (cmd->codecId)
852 {
853#if defined(WITH_GFX_AV1) || defined(WITH_GFX_AV2)
854 case RDPGFX_CODECID_AV1:
855#endif
856#if defined(WITH_GFX_AZURE)
857 case RDPGFX_CODECID_HEVC420:
858 case RDPGFX_CODECID_HEVC444:
859 {
860 const RDPGFX_HEVC_BITMAP_STREAM* hevc = (RDPGFX_HEVC_BITMAP_STREAM*)cmd->extra;
861 error = rdpgfx_write_hevc(log, s, hevc);
862
863 if (error != CHANNEL_RC_OK)
864 {
865 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
866 return error;
867 }
868 }
869 break;
870#endif
871 case RDPGFX_CODECID_AVC420:
872 {
873 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
874 error = rdpgfx_write_h264_avc420(log, s, havc420);
875
876 if (error != CHANNEL_RC_OK)
877 {
878 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
879 return error;
880 }
881 }
882 break;
883
884 case RDPGFX_CODECID_AVC444:
885 case RDPGFX_CODECID_AVC444v2:
886 {
887 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
888 havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */
889 if (!Stream_EnsureRemainingCapacity(s, 4))
890 return ERROR_INTERNAL_ERROR;
891 Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 |
892 ((uint32_t)havc444->LC << 30UL));
893 /* avc420EncodedBitstream1 */
894 error = rdpgfx_write_h264_avc420(log, s, havc420);
895
896 if (error != CHANNEL_RC_OK)
897 {
898 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
899 return error;
900 }
901
902 /* avc420EncodedBitstream2 */
903 if (havc444->LC == 0)
904 {
905 havc420 = &(havc444->bitstream[1]);
906 error = rdpgfx_write_h264_avc420(log, s, havc420);
907
908 if (error != CHANNEL_RC_OK)
909 {
910 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
911 return error;
912 }
913 }
914 }
915 break;
916 default:
917 if (!Stream_EnsureRemainingCapacity(s, cmd->length))
918 return ERROR_INTERNAL_ERROR;
919 Stream_Write(s, cmd->data, cmd->length);
920 break;
921 }
922
923 /* Fill actual bitmap data length */
924 const size_t bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart;
925 if (bitmapDataLength > UINT32_MAX)
926 return ERROR_INTERNAL_ERROR;
927
928 if (!Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32)))
929 return ERROR_INVALID_DATA;
930 if (!Stream_EnsureRemainingCapacity(s, 4))
931 return ERROR_INTERNAL_ERROR;
932 Stream_Write_UINT32(s, (UINT32)bitmapDataLength); /* bitmapDataLength (4 bytes) */
933 if (!Stream_SafeSeek(s, bitmapDataLength))
934 return ERROR_INTERNAL_ERROR;
935 }
936
937 return error;
938}
939
947WINPR_ATTR_NODISCARD static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context,
948 const RDPGFX_SURFACE_COMMAND* cmd)
949{
950 if (!checkCapsAreExchanged(context))
951 return CHANNEL_RC_NOT_INITIALIZED;
952 UINT error = CHANNEL_RC_OK;
953
954 WINPR_ASSERT(context);
955 WINPR_ASSERT(context->priv);
956 WINPR_ASSERT(cmd);
957
958 wStream* s =
959 rdpgfx_server_single_packet_new(context->priv->log, rdpgfx_surface_command_cmdid(cmd),
960 rdpgfx_estimate_surface_command(cmd));
961
962 if (!s)
963 {
964 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
965 return CHANNEL_RC_NO_MEMORY;
966 }
967
968 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
969
970 if (error != CHANNEL_RC_OK)
971 {
972 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
973 goto error;
974 }
975
976 return rdpgfx_server_single_packet_send(context, s);
977error:
978 Stream_Free(s, TRUE);
979 return error;
980}
981
990WINPR_ATTR_NODISCARD static UINT
991rdpgfx_send_surface_frame_command(RdpgfxServerContext* context, const RDPGFX_SURFACE_COMMAND* cmd,
992 const RDPGFX_START_FRAME_PDU* startFrame,
993 const RDPGFX_END_FRAME_PDU* endFrame)
994
995{
996 if (!checkCapsAreExchanged(context))
997 return CHANNEL_RC_NOT_INITIALIZED;
998
999 WINPR_ASSERT(context->priv);
1000 WINPR_ASSERT(cmd);
1001 WINPR_ASSERT(startFrame);
1002 WINPR_ASSERT(endFrame);
1003
1004 UINT error = CHANNEL_RC_OK;
1005 size_t size = rdpgfx_pdu_length(rdpgfx_estimate_surface_command(cmd));
1006
1007 if (startFrame)
1008 {
1009 size += rdpgfx_pdu_length(RDPGFX_START_FRAME_PDU_SIZE);
1010 }
1011
1012 if (endFrame)
1013 {
1014 size += rdpgfx_pdu_length(RDPGFX_END_FRAME_PDU_SIZE);
1015 }
1016
1017 wStream* s = Stream_New(nullptr, size);
1018
1019 if (!s)
1020 {
1021 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
1022 return CHANNEL_RC_NO_MEMORY;
1023 }
1024
1025 /* Write start frame if exists */
1026 if (startFrame)
1027 {
1028 const size_t position = Stream_GetPosition(s);
1029 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_STARTFRAME, 0);
1030
1031 if (error != CHANNEL_RC_OK)
1032 {
1033 WLog_Print(context->priv->log, WLOG_ERROR,
1034 "Failed to init header with error %" PRIu32 "!", error);
1035 goto error;
1036 }
1037
1038 if (!rdpgfx_write_start_frame_pdu(s, startFrame) ||
1039 !rdpgfx_server_packet_complete_header(s, position))
1040 {
1041 error = ERROR_INTERNAL_ERROR;
1042 goto error;
1043 }
1044 }
1045
1046 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */
1047 {
1048 const size_t pos = Stream_GetPosition(s);
1049 error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd),
1050 0); // Actual length will be filled later
1051
1052 if (error != CHANNEL_RC_OK)
1053 {
1054 WLog_Print(context->priv->log, WLOG_ERROR,
1055 "Failed to init header with error %" PRIu32 "!", error);
1056 goto error;
1057 }
1058
1059 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
1060
1061 if (error != CHANNEL_RC_OK)
1062 {
1063 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
1064 goto error;
1065 }
1066
1067 if (!rdpgfx_server_packet_complete_header(s, pos))
1068 {
1069 error = ERROR_INTERNAL_ERROR;
1070 goto error;
1071 }
1072 }
1073
1074 /* Write end frame if exists */
1075 if (endFrame)
1076 {
1077 const size_t position = Stream_GetPosition(s);
1078 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0);
1079
1080 if (error != CHANNEL_RC_OK)
1081 {
1082 WLog_Print(context->priv->log, WLOG_ERROR,
1083 "Failed to init header with error %" PRIu32 "!", error);
1084 goto error;
1085 }
1086
1087 if (!rdpgfx_write_end_frame_pdu(s, endFrame) ||
1088 !rdpgfx_server_packet_complete_header(s, position))
1089 {
1090 error = ERROR_INTERNAL_ERROR;
1091 goto error;
1092 }
1093 }
1094
1095 return rdpgfx_server_packet_send(context, s);
1096error:
1097 Stream_Free(s, TRUE);
1098 return error;
1099}
1100
1106WINPR_ATTR_NODISCARD static UINT
1107rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context,
1109{
1110 if (!checkCapsAreExchanged(context))
1111 return CHANNEL_RC_NOT_INITIALIZED;
1112
1113 WINPR_ASSERT(context->priv);
1114 WINPR_ASSERT(pdu);
1115 wStream* s =
1116 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6);
1117
1118 if (!s)
1119 {
1120 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1121 return CHANNEL_RC_NO_MEMORY;
1122 }
1123
1124 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1125 Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */
1126 return rdpgfx_server_single_packet_send(context, s);
1127}
1128
1134WINPR_ATTR_NODISCARD static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context,
1135 const RDPGFX_SOLID_FILL_PDU* pdu)
1136{
1137 if (!checkCapsAreExchanged(context))
1138 return CHANNEL_RC_NOT_INITIALIZED;
1139
1140 WINPR_ASSERT(context->priv);
1141 WINPR_ASSERT(pdu);
1142
1143 UINT error = CHANNEL_RC_OK;
1144 RECTANGLE_16* fillRect = nullptr;
1145 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SOLIDFILL,
1146 8 + 8 * pdu->fillRectCount);
1147
1148 if (!s)
1149 {
1150 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1151 return CHANNEL_RC_NO_MEMORY;
1152 }
1153
1154 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1155
1156 /* fillPixel (4 bytes) */
1157 if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel))))
1158 {
1159 WLog_Print(context->priv->log, WLOG_ERROR,
1160 "rdpgfx_write_color32 failed with error %" PRIu32 "!", error);
1161 goto error;
1162 }
1163
1164 Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */
1165
1166 for (UINT16 index = 0; index < pdu->fillRectCount; index++)
1167 {
1168 fillRect = &(pdu->fillRects[index]);
1169
1170 if ((error = rdpgfx_write_rect16(s, fillRect)))
1171 {
1172 WLog_Print(context->priv->log, WLOG_ERROR,
1173 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1174 goto error;
1175 }
1176 }
1177
1178 return rdpgfx_server_single_packet_send(context, s);
1179error:
1180 Stream_Free(s, TRUE);
1181 return error;
1182}
1183
1189WINPR_ATTR_NODISCARD static UINT
1190rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context,
1192{
1193 if (!checkCapsAreExchanged(context))
1194 return CHANNEL_RC_NOT_INITIALIZED;
1195
1196 WINPR_ASSERT(pdu);
1197 WINPR_ASSERT(context->priv);
1198
1199 UINT error = CHANNEL_RC_OK;
1200 RDPGFX_POINT16* destPt = nullptr;
1201 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOSURFACE,
1202 14 + 4 * pdu->destPtsCount);
1203
1204 if (!s)
1205 {
1206 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1207 return CHANNEL_RC_NO_MEMORY;
1208 }
1209
1210 Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
1211 Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */
1212
1213 /* rectSrc (8 bytes ) */
1214 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1215 {
1216 WLog_Print(context->priv->log, WLOG_ERROR,
1217 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1218 goto error;
1219 }
1220
1221 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1222
1223 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1224 {
1225 destPt = &(pdu->destPts[index]);
1226
1227 if ((error = rdpgfx_write_point16(s, destPt)))
1228 {
1229 WLog_Print(context->priv->log, WLOG_ERROR,
1230 "rdpgfx_write_point16 failed with error %" PRIu32 "!", error);
1231 goto error;
1232 }
1233 }
1234
1235 return rdpgfx_server_single_packet_send(context, s);
1236error:
1237 Stream_Free(s, TRUE);
1238 return error;
1239}
1240
1246WINPR_ATTR_NODISCARD static UINT
1247rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context,
1248 const RDPGFX_SURFACE_TO_CACHE_PDU* pdu)
1249{
1250 if (!checkCapsAreExchanged(context))
1251 return CHANNEL_RC_NOT_INITIALIZED;
1252
1253 WINPR_ASSERT(pdu);
1254 WINPR_ASSERT(context->priv);
1255
1256 UINT error = CHANNEL_RC_OK;
1257 wStream* s =
1258 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOCACHE, 20);
1259
1260 if (!s)
1261 {
1262 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1263 return CHANNEL_RC_NO_MEMORY;
1264 }
1265
1266 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1267 Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */
1268 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1269
1270 /* rectSrc (8 bytes ) */
1271 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1272 {
1273 WLog_Print(context->priv->log, WLOG_ERROR,
1274 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1275 goto error;
1276 }
1277
1278 return rdpgfx_server_single_packet_send(context, s);
1279error:
1280 Stream_Free(s, TRUE);
1281 return error;
1282}
1283
1289WINPR_ATTR_NODISCARD static UINT
1290rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context,
1291 const RDPGFX_CACHE_TO_SURFACE_PDU* pdu)
1292{
1293 if (!checkCapsAreExchanged(context))
1294 return CHANNEL_RC_NOT_INITIALIZED;
1295
1296 WINPR_ASSERT(pdu);
1297 WINPR_ASSERT(context->priv);
1298
1299 UINT error = CHANNEL_RC_OK;
1300 RDPGFX_POINT16* destPt = nullptr;
1301 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHETOSURFACE,
1302 6 + 4 * pdu->destPtsCount);
1303
1304 if (!s)
1305 {
1306 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1307 return CHANNEL_RC_NO_MEMORY;
1308 }
1309
1310 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1311 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1312 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1313
1314 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1315 {
1316 destPt = &(pdu->destPts[index]);
1317
1318 if ((error = rdpgfx_write_point16(s, destPt)))
1319 {
1320 WLog_Print(context->priv->log, WLOG_ERROR,
1321 "rdpgfx_write_point16 failed with error %" PRIu32 "", error);
1322 goto error;
1323 }
1324 }
1325
1326 return rdpgfx_server_single_packet_send(context, s);
1327error:
1328 Stream_Free(s, TRUE);
1329 return error;
1330}
1331
1337WINPR_ATTR_NODISCARD static UINT
1338rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context,
1340{
1341 if (!checkCapsAreExchanged(context))
1342 return CHANNEL_RC_NOT_INITIALIZED;
1343
1344 WINPR_ASSERT(pdu);
1345 WINPR_ASSERT(context->priv);
1346 wStream* s =
1347 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12);
1348
1349 if (!s)
1350 {
1351 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1352 return CHANNEL_RC_NO_MEMORY;
1353 }
1354
1355 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1356 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1357 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1358 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1359 return rdpgfx_server_single_packet_send(context, s);
1360}
1361
1367WINPR_ATTR_NODISCARD static UINT
1368rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context,
1370{
1371 if (!checkCapsAreExchanged(context))
1372 return CHANNEL_RC_NOT_INITIALIZED;
1373
1374 WINPR_ASSERT(pdu);
1375 WINPR_ASSERT(context->priv);
1376
1377 wStream* s =
1378 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOWINDOW, 18);
1379
1380 if (!s)
1381 {
1382 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1383 return CHANNEL_RC_NO_MEMORY;
1384 }
1385
1386 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1387 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1388 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1389 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1390 return rdpgfx_server_single_packet_send(context, s);
1391}
1392
1393WINPR_ATTR_NODISCARD static UINT
1394rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context,
1396{
1397 if (!checkCapsAreExchanged(context))
1398 return CHANNEL_RC_NOT_INITIALIZED;
1399
1400 WINPR_ASSERT(pdu);
1401 WINPR_ASSERT(context->priv);
1402 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1403 RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26);
1404
1405 if (!s)
1406 {
1407 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1408 return CHANNEL_RC_NO_MEMORY;
1409 }
1410
1411 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1412 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1413 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1414 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1415 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1416 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1417 return rdpgfx_server_single_packet_send(context, s);
1418}
1419
1425WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context,
1426 wStream* s)
1427{
1428 WINPR_ASSERT(context);
1429
1430 if (!checkCapsAreExchanged(context))
1431 return CHANNEL_RC_NOT_INITIALIZED;
1432
1433 WINPR_ASSERT(context->priv);
1434
1435 RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu = WINPR_C_ARRAY_INIT;
1436 UINT error = CHANNEL_RC_OK;
1437
1438 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1439 return ERROR_INVALID_DATA;
1440
1441 Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */
1442 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1443 Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
1444
1445 IFCALLRET(context->FrameAcknowledge, error, context, &pdu);
1446
1447 if (error)
1448 WLog_Print(context->priv->log, WLOG_ERROR,
1449 "context->FrameAcknowledge failed with error %" PRIu32 "", error);
1450
1451 return error;
1452}
1453
1459WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context,
1460 wStream* s)
1461{
1462 WINPR_ASSERT(context);
1463 if (!checkCapsAreExchanged(context))
1464 return CHANNEL_RC_NOT_INITIALIZED;
1465
1466 WINPR_ASSERT(context->priv);
1467
1468 RDPGFX_CACHE_IMPORT_OFFER_PDU pdu = WINPR_C_ARRAY_INIT;
1469 RDPGFX_CACHE_ENTRY_METADATA* cacheEntry = nullptr;
1470 UINT error = CHANNEL_RC_OK;
1471
1472 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1473 return ERROR_INVALID_DATA;
1474
1475 /* cacheEntriesCount (2 bytes) */
1476 Stream_Read_UINT16(s, pdu.cacheEntriesCount);
1477
1478 /* 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU */
1479 if (pdu.cacheEntriesCount >= 5462)
1480 {
1481 WLog_Print(context->priv->log, WLOG_ERROR, "Invalid cacheEntriesCount: %" PRIu16 "",
1482 pdu.cacheEntriesCount);
1483 return ERROR_INVALID_DATA;
1484 }
1485
1486 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(context->priv->log, s, pdu.cacheEntriesCount,
1487 12ull))
1488 return ERROR_INVALID_DATA;
1489
1490 for (UINT16 index = 0; index < pdu.cacheEntriesCount; index++)
1491 {
1492 cacheEntry = &(pdu.cacheEntries[index]);
1493 Stream_Read_UINT64(s, cacheEntry->cacheKey); /* cacheKey (8 bytes) */
1494 Stream_Read_UINT32(s, cacheEntry->bitmapLength); /* bitmapLength (4 bytes) */
1495 }
1496
1497 IFCALLRET(context->CacheImportOffer, error, context, &pdu);
1498
1499 if (error)
1500 WLog_Print(context->priv->log, WLOG_ERROR,
1501 "context->CacheImportOffer failed with error %" PRIu32 "", error);
1502
1503 return error;
1504}
1505
1511WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context,
1512 wStream* s)
1513{
1514 RDPGFX_CAPSET* capsSets = nullptr;
1515 RDPGFX_CAPS_ADVERTISE_PDU pdu = WINPR_C_ARRAY_INIT;
1516 UINT error = ERROR_INVALID_DATA;
1517
1518 if (!context)
1519 return ERROR_BAD_ARGUMENTS;
1520
1521 WINPR_ASSERT(context->priv);
1522 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1523 return ERROR_INVALID_DATA;
1524
1525 Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
1526 if (pdu.capsSetCount > 0)
1527 {
1528 capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4));
1529 if (!capsSets)
1530 return ERROR_OUTOFMEMORY;
1531 }
1532
1533 pdu.capsSets = capsSets;
1534
1535 for (UINT16 index = 0; index < pdu.capsSetCount; index++)
1536 {
1537 RDPGFX_CAPSET* capsSet = &(pdu.capsSets[index]);
1538
1539 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
1540 goto fail;
1541
1542 Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */
1543 Stream_Read_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
1544
1545 if (capsSet->length >= 4)
1546 {
1547 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1548 goto fail;
1549
1550 Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
1551 }
1552
1553 if (!Stream_SafeSeek(s, capsSet->length))
1554 goto fail;
1555 }
1556
1557 error = ERROR_BAD_CONFIGURATION;
1558 IFCALLRET(context->CapsAdvertise, error, context, &pdu);
1559
1560 if (error)
1561 WLog_Print(context->priv->log, WLOG_ERROR,
1562 "context->CapsAdvertise failed with error %" PRIu32 "", error);
1563
1564fail:
1565 free(capsSets);
1566 return error;
1567}
1568
1574WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context,
1575 wStream* s)
1576{
1577 WINPR_ASSERT(context);
1578
1579 if (!checkCapsAreExchanged(context))
1580 return CHANNEL_RC_NOT_INITIALIZED;
1581
1582 RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu = WINPR_C_ARRAY_INIT;
1583 UINT error = CHANNEL_RC_OK;
1584
1585 WINPR_ASSERT(context->priv);
1586
1587 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1588 return ERROR_INVALID_DATA;
1589
1590 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1591 Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
1592 Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */
1593 Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */
1594
1595 IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu);
1596
1597 if (error)
1598 WLog_Print(context->priv->log, WLOG_ERROR,
1599 "context->QoeFrameAcknowledge failed with error %" PRIu32 "", error);
1600
1601 return error;
1602}
1603
1604WINPR_ATTR_NODISCARD static UINT
1605rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context,
1607{
1608 if (!checkCapsAreExchanged(context))
1609 return CHANNEL_RC_NOT_INITIALIZED;
1610
1611 WINPR_ASSERT(pdu);
1612 WINPR_ASSERT(context->priv);
1613 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1614 RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20);
1615
1616 if (!s)
1617 {
1618 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1619 return CHANNEL_RC_NO_MEMORY;
1620 }
1621
1622 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1623 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1624 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1625 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1626 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1627 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1628 return rdpgfx_server_single_packet_send(context, s);
1629}
1630
1636WINPR_ATTR_NODISCARD static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context,
1637 wStream* data)
1638{
1639 size_t packetlen = 0;
1640 wStream sbuffer = WINPR_C_ARRAY_INIT;
1641 RDPGFX_HEADER header = WINPR_C_ARRAY_INIT;
1642 UINT error = CHANNEL_RC_OK;
1643
1644 WINPR_ASSERT(context);
1645 WINPR_ASSERT(context->priv);
1646
1647 if ((error = rdpgfx_read_header(context->priv->log, data, &header, &packetlen)))
1648 {
1649 WLog_Print(context->priv->log, WLOG_ERROR,
1650 "rdpgfx_read_header failed with error %" PRIu32 "!", error);
1651 return error;
1652 }
1653
1654 /* Limit the PDU parsers to the data of this PDU, the stream might contain more of them */
1655 wStream* s = Stream_StaticConstInit(&sbuffer, Stream_ConstPointer(data), packetlen);
1656 Stream_Seek(data, packetlen);
1657
1658 WLog_Print(context->priv->log, WLOG_TRACE,
1659 "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "",
1660 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
1661 header.pduLength);
1662
1663 switch (header.cmdId)
1664 {
1665 case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
1666 if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
1667 WLog_Print(context->priv->log, WLOG_ERROR,
1668 "rdpgfx_recv_frame_acknowledge_pdu "
1669 "failed with error %" PRIu32 "!",
1670 error);
1671
1672 break;
1673
1674 case RDPGFX_CMDID_CACHEIMPORTOFFER:
1675 if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
1676 WLog_Print(context->priv->log, WLOG_ERROR,
1677 "rdpgfx_recv_cache_import_offer_pdu "
1678 "failed with error %" PRIu32 "!",
1679 error);
1680
1681 break;
1682
1683 case RDPGFX_CMDID_CAPSADVERTISE:
1684 if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
1685 WLog_Print(context->priv->log, WLOG_ERROR,
1686 "rdpgfx_recv_caps_advertise_pdu "
1687 "failed with error %" PRIu32 "!",
1688 error);
1689
1690 break;
1691
1692 case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
1693 if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
1694 WLog_Print(context->priv->log, WLOG_ERROR,
1695 "rdpgfx_recv_qoe_frame_acknowledge_pdu "
1696 "failed with error %" PRIu32 "!",
1697 error);
1698
1699 break;
1700
1701 default:
1702 error = CHANNEL_RC_BAD_PROC;
1703 break;
1704 }
1705
1706 if (error)
1707 {
1708 WLog_Print(context->priv->log, WLOG_ERROR,
1709 "Error while parsing GFX cmdId: %s (0x%04" PRIX16 ")",
1710 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
1711 return error;
1712 }
1713
1714 const size_t end = Stream_GetPosition(s);
1715
1716 if (end != packetlen)
1717 {
1718 WLog_Print(context->priv->log, WLOG_ERROR,
1719 "Unexpected gfx pdu end: Actual: %" PRIuz ", Expected: %" PRIuz "", end,
1720 packetlen);
1721 }
1722
1723 return error;
1724}
1725
1726WINPR_ATTR_NODISCARD static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
1727{
1728 RdpgfxServerContext* context = (RdpgfxServerContext*)arg;
1729 WINPR_ASSERT(context);
1730
1731 RdpgfxServerPrivate* priv = context->priv;
1732 DWORD status = 0;
1733 DWORD nCount = 0;
1734 HANDLE events[8] = WINPR_C_ARRAY_INIT;
1735 UINT error = CHANNEL_RC_OK;
1736
1737 WINPR_ASSERT(priv);
1738
1739 if (priv->ownThread)
1740 {
1741 WINPR_ASSERT(priv->stopEvent);
1742 events[nCount++] = priv->stopEvent;
1743 }
1744
1745 WINPR_ASSERT(priv->channelEvent);
1746 events[nCount++] = priv->channelEvent;
1747
1748 /* Main virtual channel loop. RDPGFX do not need version negotiation */
1749 while (TRUE)
1750 {
1751 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1752
1753 if (status == WAIT_FAILED)
1754 {
1755 error = GetLastError();
1756 WLog_Print(context->priv->log, WLOG_ERROR,
1757 "WaitForMultipleObjects failed with error %" PRIu32 "", error);
1758 break;
1759 }
1760
1761 /* Stop Event */
1762 if (status == WAIT_OBJECT_0)
1763 break;
1764
1765 if ((error = rdpgfx_server_handle_messages(context)))
1766 {
1767 WLog_Print(context->priv->log, WLOG_ERROR,
1768 "rdpgfx_server_handle_messages failed with error %" PRIu32 "", error);
1769 break;
1770 }
1771 }
1772
1773 if (error && context->rdpcontext)
1774 setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error");
1775
1776 ExitThread(error);
1777 return error;
1778}
1779
1780WINPR_ATTR_NODISCARD static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
1781{
1782 WINPR_ASSERT(context);
1783 RdpgfxServerPrivate* priv = context->priv;
1784 void* buffer = nullptr;
1785
1786 WINPR_ASSERT(priv);
1787
1788 if (!priv->isOpened)
1789 {
1790 PULONG pSessionId = nullptr;
1791 DWORD BytesReturned = 0;
1792 priv->SessionId = WTS_CURRENT_SESSION;
1793 UINT32 channelId = 0;
1794 BOOL status = TRUE;
1795
1796 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
1797 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
1798 {
1799 WLog_Print(context->priv->log, WLOG_ERROR, "WTSQuerySessionInformationA failed!");
1800 return FALSE;
1801 }
1802
1803 priv->SessionId = (DWORD)*pSessionId;
1804 WTSFreeMemory(pSessionId);
1805 priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME,
1806 WTS_CHANNEL_OPTION_DYNAMIC);
1807
1808 if (!priv->rdpgfx_channel)
1809 {
1810 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelOpenEx failed!");
1811 return FALSE;
1812 }
1813
1814 channelId = WTSChannelGetIdByHandle(priv->rdpgfx_channel);
1815
1816 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
1817 if (!status)
1818 {
1819 WLog_Print(context->priv->log, WLOG_ERROR, "context->ChannelIdAssigned failed!");
1820 goto fail;
1821 }
1822
1823 /* Query for channel event handle */
1824 if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
1825 &BytesReturned) ||
1826 (BytesReturned != sizeof(HANDLE)))
1827 {
1828 WLog_Print(context->priv->log, WLOG_ERROR,
1829 "WTSVirtualChannelQuery failed "
1830 "or invalid returned size(%" PRIu32 ")",
1831 BytesReturned);
1832
1833 if (buffer)
1834 WTSFreeMemory(buffer);
1835
1836 goto fail;
1837 }
1838
1839 priv->channelEvent = *(HANDLE*)buffer;
1840 WTSFreeMemory(buffer);
1841
1842 if (!(priv->zgfx = zgfx_context_new(TRUE)))
1843 {
1844 WLog_Print(context->priv->log, WLOG_ERROR, "Create zgfx context failed!");
1845 goto fail;
1846 }
1847
1848 priv->isReady = FALSE;
1849 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1850 priv->activeCapSet = empty;
1851 if (priv->ownThread)
1852 {
1853 if (!(priv->stopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
1854 {
1855 WLog_Print(context->priv->log, WLOG_ERROR, "CreateEvent failed!");
1856 goto fail;
1857 }
1858
1859 if (!(priv->thread = CreateThread(nullptr, 0, rdpgfx_server_thread_func, (void*)context,
1860 0, nullptr)))
1861 {
1862 WLog_Print(context->priv->log, WLOG_ERROR, "CreateThread failed!");
1863 goto fail;
1864 }
1865 }
1866
1867 priv->isOpened = TRUE;
1868 return TRUE;
1869 }
1870
1871 WLog_Print(context->priv->log, WLOG_ERROR, "RDPGFX channel is already opened!");
1872 return FALSE;
1873fail:
1874 (void)rdpgfx_server_close(context);
1875 return FALSE;
1876}
1877
1878BOOL rdpgfx_server_close(RdpgfxServerContext* context)
1879{
1880 WINPR_ASSERT(context);
1881
1882 RdpgfxServerPrivate* priv = context->priv;
1883 WINPR_ASSERT(priv);
1884
1885 if (priv->ownThread && priv->thread)
1886 {
1887 (void)SetEvent(priv->stopEvent);
1888
1889 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
1890 {
1891 WLog_Print(context->priv->log, WLOG_ERROR,
1892 "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
1893 return FALSE;
1894 }
1895
1896 (void)CloseHandle(priv->thread);
1897 (void)CloseHandle(priv->stopEvent);
1898 priv->thread = nullptr;
1899 priv->stopEvent = nullptr;
1900 }
1901
1902 zgfx_context_free(priv->zgfx);
1903 priv->zgfx = nullptr;
1904
1905 if (priv->rdpgfx_channel)
1906 {
1907 (void)WTSVirtualChannelClose(priv->rdpgfx_channel);
1908 priv->rdpgfx_channel = nullptr;
1909 }
1910
1911 priv->channelEvent = nullptr;
1912 priv->isOpened = FALSE;
1913 priv->isReady = FALSE;
1914 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1915 priv->activeCapSet = empty;
1916 return TRUE;
1917}
1918
1919WINPR_ATTR_NODISCARD static BOOL rdpgfx_server_initialize(RdpgfxServerContext* context,
1920 BOOL externalThread)
1921{
1922 WINPR_ASSERT(context);
1923 WINPR_ASSERT(context->priv);
1924
1925 if (context->priv->isOpened)
1926 {
1927 WLog_Print(context->priv->log, WLOG_WARN,
1928 "Application error: RDPEGFX channel already initialized, "
1929 "calling in this state is not possible!");
1930 return FALSE;
1931 }
1932
1933 context->priv->ownThread = !externalThread;
1934 return TRUE;
1935}
1936
1937RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm)
1938{
1939 RdpgfxServerContext* context = (RdpgfxServerContext*)calloc(1, sizeof(RdpgfxServerContext));
1940
1941 if (!context)
1942 return nullptr;
1943
1944 context->vcm = vcm;
1945 context->Initialize = rdpgfx_server_initialize;
1946 context->Open = rdpgfx_server_open;
1947 context->Close = rdpgfx_server_close;
1948 context->ResetGraphics = rdpgfx_send_reset_graphics_pdu;
1949 context->StartFrame = rdpgfx_send_start_frame_pdu;
1950 context->EndFrame = rdpgfx_send_end_frame_pdu;
1951 context->SurfaceCommand = rdpgfx_send_surface_command;
1952 context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command;
1953 context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu;
1954 context->CreateSurface = rdpgfx_send_create_surface_pdu;
1955 context->DeleteSurface = rdpgfx_send_delete_surface_pdu;
1956 context->SolidFill = rdpgfx_send_solid_fill_pdu;
1957 context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu;
1958 context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu;
1959 context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu;
1960 context->CacheImportOffer = rdpgfx_process_cache_import_offer_pdu;
1961 context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu;
1962 context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu;
1963 context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu;
1964 context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu;
1965 context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu;
1966 context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu;
1967 context->CapsAdvertise = nullptr;
1968 context->CapsConfirm = rdpgfx_send_caps_confirm_pdu;
1969 context->FrameAcknowledge = nullptr;
1970 context->QoeFrameAcknowledge = nullptr;
1971 RdpgfxServerPrivate* priv = context->priv =
1972 (RdpgfxServerPrivate*)calloc(1, sizeof(RdpgfxServerPrivate));
1973
1974 if (!priv)
1975 goto fail;
1976
1977 priv->log = WLog_Get(TAG);
1978 if (!priv->log)
1979 goto fail;
1980
1981 /* Create shared input stream */
1982 priv->input_stream = Stream_New(nullptr, 4);
1983
1984 if (!priv->input_stream)
1985 {
1986 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
1987 goto fail;
1988 }
1989
1990 priv->isOpened = FALSE;
1991 priv->isReady = FALSE;
1992 priv->ownThread = TRUE;
1993
1994 {
1995 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1996 priv->activeCapSet = empty;
1997 }
1998
1999 return context;
2000fail:
2001 WINPR_PRAGMA_DIAG_PUSH
2002 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2003 rdpgfx_server_context_free(context);
2004 WINPR_PRAGMA_DIAG_POP
2005 return nullptr;
2006}
2007
2008void rdpgfx_server_context_free(RdpgfxServerContext* context)
2009{
2010 if (!context)
2011 return;
2012
2013 (void)rdpgfx_server_close(context);
2014
2015 if (context->priv)
2016 Stream_Free(context->priv->input_stream, TRUE);
2017
2018 free(context->priv);
2019 free(context);
2020}
2021
2022HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context)
2023{
2024 if (!context)
2025 return nullptr;
2026 if (!context->priv)
2027 return nullptr;
2028 return context->priv->channelEvent;
2029}
2030
2031/*
2032 * Handle rpdgfx messages - server side
2033 *
2034 * @param context side context
2035 *
2036 * @return 0 on success
2037 * ERROR_NO_DATA if no data could be read this time
2038 * otherwise a Win32 error code
2039 */
2040UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
2041{
2042 DWORD BytesReturned = 0;
2043 void* buffer = nullptr;
2044 UINT ret = CHANNEL_RC_OK;
2045
2046 WINPR_ASSERT(context);
2047 WINPR_ASSERT(context->priv);
2048
2049 RdpgfxServerPrivate* priv = context->priv;
2050 wStream* s = priv->input_stream;
2051
2052 /* Check whether the dynamic channel is ready */
2053 if (!priv->isReady)
2054 {
2055 if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer,
2056 &BytesReturned) == FALSE)
2057 {
2058 if (GetLastError() == ERROR_NO_DATA)
2059 return ERROR_NO_DATA;
2060
2061 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
2062 return ERROR_INTERNAL_ERROR;
2063 }
2064
2065 priv->isReady = *((BOOL*)buffer);
2066 WTSFreeMemory(buffer);
2067 }
2068
2069 /* Consume channel event only after the gfx dynamic channel is ready */
2070 if (priv->isReady)
2071 {
2072 Stream_ResetPosition(s);
2073
2074 if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, nullptr, 0, &BytesReturned))
2075 {
2076 if (GetLastError() == ERROR_NO_DATA)
2077 return ERROR_NO_DATA;
2078
2079 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
2080 return ERROR_INTERNAL_ERROR;
2081 }
2082
2083 if (BytesReturned < 1)
2084 return CHANNEL_RC_OK;
2085
2086 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
2087 {
2088 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
2089 return CHANNEL_RC_NO_MEMORY;
2090 }
2091
2092 const size_t len = Stream_Capacity(s);
2093 if (len > UINT32_MAX)
2094 return ERROR_INTERNAL_ERROR;
2095 if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, Stream_BufferAs(s, char), (UINT32)len,
2096 &BytesReturned) == FALSE)
2097 {
2098 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
2099 return ERROR_INTERNAL_ERROR;
2100 }
2101
2102 if (!Stream_SetLength(s, BytesReturned))
2103 return ERROR_INTERNAL_ERROR;
2104
2105 Stream_ResetPosition(s);
2106
2107 while (Stream_GetPosition(s) < Stream_Length(s))
2108 {
2109 if ((ret = rdpgfx_server_receive_pdu(context, s)))
2110 {
2111 WLog_Print(context->priv->log, WLOG_ERROR,
2112 "rdpgfx_server_receive_pdu "
2113 "failed with error %" PRIu32 "!",
2114 ret);
2115 return ret;
2116 }
2117 }
2118 }
2119
2120 return ret;
2121}