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 goto error;
956 }
957
958 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */
959 {
960 const size_t pos = Stream_GetPosition(s);
961 error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd),
962 0); // Actual length will be filled later
963
964 if (error != CHANNEL_RC_OK)
965 {
966 WLog_Print(context->priv->log, WLOG_ERROR,
967 "Failed to init header with error %" PRIu32 "!", error);
968 goto error;
969 }
970
971 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
972
973 if (error != CHANNEL_RC_OK)
974 {
975 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
976 goto error;
977 }
978
979 if (!rdpgfx_server_packet_complete_header(s, pos))
980 goto error;
981 }
982
983 /* Write end frame if exists */
984 if (endFrame)
985 {
986 const size_t position = Stream_GetPosition(s);
987 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0);
988
989 if (error != CHANNEL_RC_OK)
990 {
991 WLog_Print(context->priv->log, WLOG_ERROR,
992 "Failed to init header with error %" PRIu32 "!", error);
993 goto error;
994 }
995
996 if (!rdpgfx_write_end_frame_pdu(s, endFrame) ||
997 !rdpgfx_server_packet_complete_header(s, position))
998 goto error;
999 }
1000
1001 return rdpgfx_server_packet_send(context, s);
1002error:
1003 Stream_Free(s, TRUE);
1004 return error;
1005}
1006
1012WINPR_ATTR_NODISCARD static UINT
1013rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context,
1015{
1016 if (!checkCapsAreExchanged(context))
1017 return CHANNEL_RC_NOT_INITIALIZED;
1018
1019 WINPR_ASSERT(context->priv);
1020 WINPR_ASSERT(pdu);
1021 wStream* s =
1022 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6);
1023
1024 if (!s)
1025 {
1026 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1027 return CHANNEL_RC_NO_MEMORY;
1028 }
1029
1030 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1031 Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */
1032 return rdpgfx_server_single_packet_send(context, s);
1033}
1034
1040WINPR_ATTR_NODISCARD static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context,
1041 const RDPGFX_SOLID_FILL_PDU* pdu)
1042{
1043 if (!checkCapsAreExchanged(context))
1044 return CHANNEL_RC_NOT_INITIALIZED;
1045
1046 WINPR_ASSERT(context->priv);
1047 WINPR_ASSERT(pdu);
1048
1049 UINT error = CHANNEL_RC_OK;
1050 RECTANGLE_16* fillRect = nullptr;
1051 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SOLIDFILL,
1052 8 + 8 * pdu->fillRectCount);
1053
1054 if (!s)
1055 {
1056 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1057 return CHANNEL_RC_NO_MEMORY;
1058 }
1059
1060 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1061
1062 /* fillPixel (4 bytes) */
1063 if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel))))
1064 {
1065 WLog_Print(context->priv->log, WLOG_ERROR,
1066 "rdpgfx_write_color32 failed with error %" PRIu32 "!", error);
1067 goto error;
1068 }
1069
1070 Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */
1071
1072 for (UINT16 index = 0; index < pdu->fillRectCount; index++)
1073 {
1074 fillRect = &(pdu->fillRects[index]);
1075
1076 if ((error = rdpgfx_write_rect16(s, fillRect)))
1077 {
1078 WLog_Print(context->priv->log, WLOG_ERROR,
1079 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1080 goto error;
1081 }
1082 }
1083
1084 return rdpgfx_server_single_packet_send(context, s);
1085error:
1086 Stream_Free(s, TRUE);
1087 return error;
1088}
1089
1095WINPR_ATTR_NODISCARD static UINT
1096rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context,
1098{
1099 if (!checkCapsAreExchanged(context))
1100 return CHANNEL_RC_NOT_INITIALIZED;
1101
1102 WINPR_ASSERT(pdu);
1103 WINPR_ASSERT(context->priv);
1104
1105 UINT error = CHANNEL_RC_OK;
1106 RDPGFX_POINT16* destPt = nullptr;
1107 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOSURFACE,
1108 14 + 4 * pdu->destPtsCount);
1109
1110 if (!s)
1111 {
1112 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1113 return CHANNEL_RC_NO_MEMORY;
1114 }
1115
1116 Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
1117 Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */
1118
1119 /* rectSrc (8 bytes ) */
1120 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1121 {
1122 WLog_Print(context->priv->log, WLOG_ERROR,
1123 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1124 goto error;
1125 }
1126
1127 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1128
1129 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1130 {
1131 destPt = &(pdu->destPts[index]);
1132
1133 if ((error = rdpgfx_write_point16(s, destPt)))
1134 {
1135 WLog_Print(context->priv->log, WLOG_ERROR,
1136 "rdpgfx_write_point16 failed with error %" PRIu32 "!", error);
1137 goto error;
1138 }
1139 }
1140
1141 return rdpgfx_server_single_packet_send(context, s);
1142error:
1143 Stream_Free(s, TRUE);
1144 return error;
1145}
1146
1152WINPR_ATTR_NODISCARD static UINT
1153rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context,
1154 const RDPGFX_SURFACE_TO_CACHE_PDU* pdu)
1155{
1156 if (!checkCapsAreExchanged(context))
1157 return CHANNEL_RC_NOT_INITIALIZED;
1158
1159 WINPR_ASSERT(pdu);
1160 WINPR_ASSERT(context->priv);
1161
1162 UINT error = CHANNEL_RC_OK;
1163 wStream* s =
1164 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOCACHE, 20);
1165
1166 if (!s)
1167 {
1168 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1169 return CHANNEL_RC_NO_MEMORY;
1170 }
1171
1172 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1173 Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */
1174 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1175
1176 /* rectSrc (8 bytes ) */
1177 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1178 {
1179 WLog_Print(context->priv->log, WLOG_ERROR,
1180 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1181 goto error;
1182 }
1183
1184 return rdpgfx_server_single_packet_send(context, s);
1185error:
1186 Stream_Free(s, TRUE);
1187 return error;
1188}
1189
1195WINPR_ATTR_NODISCARD static UINT
1196rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context,
1197 const RDPGFX_CACHE_TO_SURFACE_PDU* pdu)
1198{
1199 if (!checkCapsAreExchanged(context))
1200 return CHANNEL_RC_NOT_INITIALIZED;
1201
1202 WINPR_ASSERT(pdu);
1203 WINPR_ASSERT(context->priv);
1204
1205 UINT error = CHANNEL_RC_OK;
1206 RDPGFX_POINT16* destPt = nullptr;
1207 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHETOSURFACE,
1208 6 + 4 * pdu->destPtsCount);
1209
1210 if (!s)
1211 {
1212 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1213 return CHANNEL_RC_NO_MEMORY;
1214 }
1215
1216 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1217 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1218 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1219
1220 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1221 {
1222 destPt = &(pdu->destPts[index]);
1223
1224 if ((error = rdpgfx_write_point16(s, destPt)))
1225 {
1226 WLog_Print(context->priv->log, WLOG_ERROR,
1227 "rdpgfx_write_point16 failed with error %" PRIu32 "", error);
1228 goto error;
1229 }
1230 }
1231
1232 return rdpgfx_server_single_packet_send(context, s);
1233error:
1234 Stream_Free(s, TRUE);
1235 return error;
1236}
1237
1243WINPR_ATTR_NODISCARD static UINT
1244rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context,
1246{
1247 if (!checkCapsAreExchanged(context))
1248 return CHANNEL_RC_NOT_INITIALIZED;
1249
1250 WINPR_ASSERT(pdu);
1251 WINPR_ASSERT(context->priv);
1252 wStream* s =
1253 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12);
1254
1255 if (!s)
1256 {
1257 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1258 return CHANNEL_RC_NO_MEMORY;
1259 }
1260
1261 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1262 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1263 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1264 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1265 return rdpgfx_server_single_packet_send(context, s);
1266}
1267
1273WINPR_ATTR_NODISCARD static UINT
1274rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context,
1276{
1277 if (!checkCapsAreExchanged(context))
1278 return CHANNEL_RC_NOT_INITIALIZED;
1279
1280 WINPR_ASSERT(pdu);
1281 WINPR_ASSERT(context->priv);
1282
1283 wStream* s =
1284 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOWINDOW, 18);
1285
1286 if (!s)
1287 {
1288 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1289 return CHANNEL_RC_NO_MEMORY;
1290 }
1291
1292 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1293 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1294 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1295 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1296 return rdpgfx_server_single_packet_send(context, s);
1297}
1298
1299WINPR_ATTR_NODISCARD static UINT
1300rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context,
1302{
1303 if (!checkCapsAreExchanged(context))
1304 return CHANNEL_RC_NOT_INITIALIZED;
1305
1306 WINPR_ASSERT(pdu);
1307 WINPR_ASSERT(context->priv);
1308 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1309 RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26);
1310
1311 if (!s)
1312 {
1313 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1314 return CHANNEL_RC_NO_MEMORY;
1315 }
1316
1317 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1318 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1319 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1320 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1321 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1322 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1323 return rdpgfx_server_single_packet_send(context, s);
1324}
1325
1331WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context,
1332 wStream* s)
1333{
1334 WINPR_ASSERT(context);
1335
1336 if (!checkCapsAreExchanged(context))
1337 return CHANNEL_RC_NOT_INITIALIZED;
1338
1339 WINPR_ASSERT(context->priv);
1340
1341 RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu = WINPR_C_ARRAY_INIT;
1342 UINT error = CHANNEL_RC_OK;
1343
1344 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1345 return ERROR_INVALID_DATA;
1346
1347 Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */
1348 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1349 Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
1350
1351 IFCALLRET(context->FrameAcknowledge, error, context, &pdu);
1352
1353 if (error)
1354 WLog_Print(context->priv->log, WLOG_ERROR,
1355 "context->FrameAcknowledge failed with error %" PRIu32 "", error);
1356
1357 return error;
1358}
1359
1365WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context,
1366 wStream* s)
1367{
1368 WINPR_ASSERT(context);
1369 if (!checkCapsAreExchanged(context))
1370 return CHANNEL_RC_NOT_INITIALIZED;
1371
1372 WINPR_ASSERT(context->priv);
1373
1374 RDPGFX_CACHE_IMPORT_OFFER_PDU pdu = WINPR_C_ARRAY_INIT;
1375 RDPGFX_CACHE_ENTRY_METADATA* cacheEntry = nullptr;
1376 UINT error = CHANNEL_RC_OK;
1377
1378 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1379 return ERROR_INVALID_DATA;
1380
1381 /* cacheEntriesCount (2 bytes) */
1382 Stream_Read_UINT16(s, pdu.cacheEntriesCount);
1383
1384 /* 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU */
1385 if (pdu.cacheEntriesCount >= 5462)
1386 {
1387 WLog_Print(context->priv->log, WLOG_ERROR, "Invalid cacheEntriesCount: %" PRIu16 "",
1388 pdu.cacheEntriesCount);
1389 return ERROR_INVALID_DATA;
1390 }
1391
1392 if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(context->priv->log, s, pdu.cacheEntriesCount,
1393 12ull))
1394 return ERROR_INVALID_DATA;
1395
1396 for (UINT16 index = 0; index < pdu.cacheEntriesCount; index++)
1397 {
1398 cacheEntry = &(pdu.cacheEntries[index]);
1399 Stream_Read_UINT64(s, cacheEntry->cacheKey); /* cacheKey (8 bytes) */
1400 Stream_Read_UINT32(s, cacheEntry->bitmapLength); /* bitmapLength (4 bytes) */
1401 }
1402
1403 IFCALLRET(context->CacheImportOffer, error, context, &pdu);
1404
1405 if (error)
1406 WLog_Print(context->priv->log, WLOG_ERROR,
1407 "context->CacheImportOffer failed with error %" PRIu32 "", error);
1408
1409 return error;
1410}
1411
1417WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context,
1418 wStream* s)
1419{
1420 RDPGFX_CAPSET* capsSets = nullptr;
1421 RDPGFX_CAPS_ADVERTISE_PDU pdu = WINPR_C_ARRAY_INIT;
1422 UINT error = ERROR_INVALID_DATA;
1423
1424 if (!context)
1425 return ERROR_BAD_ARGUMENTS;
1426
1427 WINPR_ASSERT(context->priv);
1428 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 2))
1429 return ERROR_INVALID_DATA;
1430
1431 Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
1432 if (pdu.capsSetCount > 0)
1433 {
1434 capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4));
1435 if (!capsSets)
1436 return ERROR_OUTOFMEMORY;
1437 }
1438
1439 pdu.capsSets = capsSets;
1440
1441 for (UINT16 index = 0; index < pdu.capsSetCount; index++)
1442 {
1443 RDPGFX_CAPSET* capsSet = &(pdu.capsSets[index]);
1444
1445 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8))
1446 goto fail;
1447
1448 Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */
1449 Stream_Read_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
1450
1451 if (capsSet->length >= 4)
1452 {
1453 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4))
1454 goto fail;
1455
1456 Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
1457 }
1458
1459 if (!Stream_SafeSeek(s, capsSet->length))
1460 goto fail;
1461 }
1462
1463 error = ERROR_BAD_CONFIGURATION;
1464 IFCALLRET(context->CapsAdvertise, error, context, &pdu);
1465
1466 if (error)
1467 WLog_Print(context->priv->log, WLOG_ERROR,
1468 "context->CapsAdvertise failed with error %" PRIu32 "", error);
1469
1470fail:
1471 free(capsSets);
1472 return error;
1473}
1474
1480WINPR_ATTR_NODISCARD static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context,
1481 wStream* s)
1482{
1483 WINPR_ASSERT(context);
1484
1485 if (!checkCapsAreExchanged(context))
1486 return CHANNEL_RC_NOT_INITIALIZED;
1487
1488 RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu = WINPR_C_ARRAY_INIT;
1489 UINT error = CHANNEL_RC_OK;
1490
1491 WINPR_ASSERT(context->priv);
1492
1493 if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12))
1494 return ERROR_INVALID_DATA;
1495
1496 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1497 Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
1498 Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */
1499 Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */
1500
1501 IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu);
1502
1503 if (error)
1504 WLog_Print(context->priv->log, WLOG_ERROR,
1505 "context->QoeFrameAcknowledge failed with error %" PRIu32 "", error);
1506
1507 return error;
1508}
1509
1510WINPR_ATTR_NODISCARD static UINT
1511rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context,
1513{
1514 if (!checkCapsAreExchanged(context))
1515 return CHANNEL_RC_NOT_INITIALIZED;
1516
1517 WINPR_ASSERT(pdu);
1518 WINPR_ASSERT(context->priv);
1519 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1520 RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20);
1521
1522 if (!s)
1523 {
1524 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1525 return CHANNEL_RC_NO_MEMORY;
1526 }
1527
1528 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1529 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1530 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1531 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1532 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1533 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1534 return rdpgfx_server_single_packet_send(context, s);
1535}
1536
1542WINPR_ATTR_NODISCARD static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
1543{
1544 size_t end = 0;
1545 RDPGFX_HEADER header = WINPR_C_ARRAY_INIT;
1546 UINT error = CHANNEL_RC_OK;
1547 size_t beg = Stream_GetPosition(s);
1548
1549 WINPR_ASSERT(context);
1550 WINPR_ASSERT(context->priv);
1551
1552 if ((error = rdpgfx_read_header(context->priv->log, s, &header)))
1553 {
1554 WLog_Print(context->priv->log, WLOG_ERROR,
1555 "rdpgfx_read_header failed with error %" PRIu32 "!", error);
1556 return error;
1557 }
1558
1559 WLog_Print(context->priv->log, WLOG_TRACE,
1560 "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "",
1561 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags,
1562 header.pduLength);
1563
1564 switch (header.cmdId)
1565 {
1566 case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
1567 if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
1568 WLog_Print(context->priv->log, WLOG_ERROR,
1569 "rdpgfx_recv_frame_acknowledge_pdu "
1570 "failed with error %" PRIu32 "!",
1571 error);
1572
1573 break;
1574
1575 case RDPGFX_CMDID_CACHEIMPORTOFFER:
1576 if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
1577 WLog_Print(context->priv->log, WLOG_ERROR,
1578 "rdpgfx_recv_cache_import_offer_pdu "
1579 "failed with error %" PRIu32 "!",
1580 error);
1581
1582 break;
1583
1584 case RDPGFX_CMDID_CAPSADVERTISE:
1585 if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
1586 WLog_Print(context->priv->log, WLOG_ERROR,
1587 "rdpgfx_recv_caps_advertise_pdu "
1588 "failed with error %" PRIu32 "!",
1589 error);
1590
1591 break;
1592
1593 case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
1594 if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
1595 WLog_Print(context->priv->log, WLOG_ERROR,
1596 "rdpgfx_recv_qoe_frame_acknowledge_pdu "
1597 "failed with error %" PRIu32 "!",
1598 error);
1599
1600 break;
1601
1602 default:
1603 error = CHANNEL_RC_BAD_PROC;
1604 break;
1605 }
1606
1607 if (error)
1608 {
1609 WLog_Print(context->priv->log, WLOG_ERROR,
1610 "Error while parsing GFX cmdId: %s (0x%04" PRIX16 ")",
1611 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
1612 return error;
1613 }
1614
1615 end = Stream_GetPosition(s);
1616
1617 if (end != (beg + header.pduLength))
1618 {
1619 WLog_Print(context->priv->log, WLOG_ERROR,
1620 "Unexpected gfx pdu end: Actual: %" PRIuz ", Expected: %" PRIuz "", end,
1621 (beg + header.pduLength));
1622 if (!Stream_SetPosition(s, (beg + header.pduLength)))
1623 return ERROR_INVALID_DATA;
1624 }
1625
1626 return error;
1627}
1628
1629WINPR_ATTR_NODISCARD static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
1630{
1631 RdpgfxServerContext* context = (RdpgfxServerContext*)arg;
1632 WINPR_ASSERT(context);
1633
1634 RdpgfxServerPrivate* priv = context->priv;
1635 DWORD status = 0;
1636 DWORD nCount = 0;
1637 HANDLE events[8] = WINPR_C_ARRAY_INIT;
1638 UINT error = CHANNEL_RC_OK;
1639
1640 WINPR_ASSERT(priv);
1641
1642 if (priv->ownThread)
1643 {
1644 WINPR_ASSERT(priv->stopEvent);
1645 events[nCount++] = priv->stopEvent;
1646 }
1647
1648 WINPR_ASSERT(priv->channelEvent);
1649 events[nCount++] = priv->channelEvent;
1650
1651 /* Main virtual channel loop. RDPGFX do not need version negotiation */
1652 while (TRUE)
1653 {
1654 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1655
1656 if (status == WAIT_FAILED)
1657 {
1658 error = GetLastError();
1659 WLog_Print(context->priv->log, WLOG_ERROR,
1660 "WaitForMultipleObjects failed with error %" PRIu32 "", error);
1661 break;
1662 }
1663
1664 /* Stop Event */
1665 if (status == WAIT_OBJECT_0)
1666 break;
1667
1668 if ((error = rdpgfx_server_handle_messages(context)))
1669 {
1670 WLog_Print(context->priv->log, WLOG_ERROR,
1671 "rdpgfx_server_handle_messages failed with error %" PRIu32 "", error);
1672 break;
1673 }
1674 }
1675
1676 if (error && context->rdpcontext)
1677 setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error");
1678
1679 ExitThread(error);
1680 return error;
1681}
1682
1683WINPR_ATTR_NODISCARD static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
1684{
1685 WINPR_ASSERT(context);
1686 RdpgfxServerPrivate* priv = context->priv;
1687 void* buffer = nullptr;
1688
1689 WINPR_ASSERT(priv);
1690
1691 if (!priv->isOpened)
1692 {
1693 PULONG pSessionId = nullptr;
1694 DWORD BytesReturned = 0;
1695 priv->SessionId = WTS_CURRENT_SESSION;
1696 UINT32 channelId = 0;
1697 BOOL status = TRUE;
1698
1699 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
1700 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
1701 {
1702 WLog_Print(context->priv->log, WLOG_ERROR, "WTSQuerySessionInformationA failed!");
1703 return FALSE;
1704 }
1705
1706 priv->SessionId = (DWORD)*pSessionId;
1707 WTSFreeMemory(pSessionId);
1708 priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME,
1709 WTS_CHANNEL_OPTION_DYNAMIC);
1710
1711 if (!priv->rdpgfx_channel)
1712 {
1713 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelOpenEx failed!");
1714 return FALSE;
1715 }
1716
1717 channelId = WTSChannelGetIdByHandle(priv->rdpgfx_channel);
1718
1719 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
1720 if (!status)
1721 {
1722 WLog_Print(context->priv->log, WLOG_ERROR, "context->ChannelIdAssigned failed!");
1723 goto fail;
1724 }
1725
1726 /* Query for channel event handle */
1727 if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
1728 &BytesReturned) ||
1729 (BytesReturned != sizeof(HANDLE)))
1730 {
1731 WLog_Print(context->priv->log, WLOG_ERROR,
1732 "WTSVirtualChannelQuery failed "
1733 "or invalid returned size(%" PRIu32 ")",
1734 BytesReturned);
1735
1736 if (buffer)
1737 WTSFreeMemory(buffer);
1738
1739 goto fail;
1740 }
1741
1742 priv->channelEvent = *(HANDLE*)buffer;
1743 WTSFreeMemory(buffer);
1744
1745 if (!(priv->zgfx = zgfx_context_new(TRUE)))
1746 {
1747 WLog_Print(context->priv->log, WLOG_ERROR, "Create zgfx context failed!");
1748 goto fail;
1749 }
1750
1751 priv->isReady = FALSE;
1752 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1753 priv->activeCapSet = empty;
1754 if (priv->ownThread)
1755 {
1756 if (!(priv->stopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
1757 {
1758 WLog_Print(context->priv->log, WLOG_ERROR, "CreateEvent failed!");
1759 goto fail;
1760 }
1761
1762 if (!(priv->thread = CreateThread(nullptr, 0, rdpgfx_server_thread_func, (void*)context,
1763 0, nullptr)))
1764 {
1765 WLog_Print(context->priv->log, WLOG_ERROR, "CreateThread failed!");
1766 goto fail;
1767 }
1768 }
1769
1770 priv->isOpened = TRUE;
1771 return TRUE;
1772 }
1773
1774 WLog_Print(context->priv->log, WLOG_ERROR, "RDPGFX channel is already opened!");
1775 return FALSE;
1776fail:
1777 (void)rdpgfx_server_close(context);
1778 return FALSE;
1779}
1780
1781BOOL rdpgfx_server_close(RdpgfxServerContext* context)
1782{
1783 WINPR_ASSERT(context);
1784
1785 RdpgfxServerPrivate* priv = context->priv;
1786 WINPR_ASSERT(priv);
1787
1788 if (priv->ownThread && priv->thread)
1789 {
1790 (void)SetEvent(priv->stopEvent);
1791
1792 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
1793 {
1794 WLog_Print(context->priv->log, WLOG_ERROR,
1795 "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
1796 return FALSE;
1797 }
1798
1799 (void)CloseHandle(priv->thread);
1800 (void)CloseHandle(priv->stopEvent);
1801 priv->thread = nullptr;
1802 priv->stopEvent = nullptr;
1803 }
1804
1805 zgfx_context_free(priv->zgfx);
1806 priv->zgfx = nullptr;
1807
1808 if (priv->rdpgfx_channel)
1809 {
1810 (void)WTSVirtualChannelClose(priv->rdpgfx_channel);
1811 priv->rdpgfx_channel = nullptr;
1812 }
1813
1814 priv->channelEvent = nullptr;
1815 priv->isOpened = FALSE;
1816 priv->isReady = FALSE;
1817 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1818 priv->activeCapSet = empty;
1819 return TRUE;
1820}
1821
1822WINPR_ATTR_NODISCARD static BOOL rdpgfx_server_initialize(RdpgfxServerContext* context,
1823 BOOL externalThread)
1824{
1825 WINPR_ASSERT(context);
1826 WINPR_ASSERT(context->priv);
1827
1828 if (context->priv->isOpened)
1829 {
1830 WLog_Print(context->priv->log, WLOG_WARN,
1831 "Application error: RDPEGFX channel already initialized, "
1832 "calling in this state is not possible!");
1833 return FALSE;
1834 }
1835
1836 context->priv->ownThread = !externalThread;
1837 return TRUE;
1838}
1839
1840RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm)
1841{
1842 RdpgfxServerContext* context = (RdpgfxServerContext*)calloc(1, sizeof(RdpgfxServerContext));
1843
1844 if (!context)
1845 return nullptr;
1846
1847 context->vcm = vcm;
1848 context->Initialize = rdpgfx_server_initialize;
1849 context->Open = rdpgfx_server_open;
1850 context->Close = rdpgfx_server_close;
1851 context->ResetGraphics = rdpgfx_send_reset_graphics_pdu;
1852 context->StartFrame = rdpgfx_send_start_frame_pdu;
1853 context->EndFrame = rdpgfx_send_end_frame_pdu;
1854 context->SurfaceCommand = rdpgfx_send_surface_command;
1855 context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command;
1856 context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu;
1857 context->CreateSurface = rdpgfx_send_create_surface_pdu;
1858 context->DeleteSurface = rdpgfx_send_delete_surface_pdu;
1859 context->SolidFill = rdpgfx_send_solid_fill_pdu;
1860 context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu;
1861 context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu;
1862 context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu;
1863 context->CacheImportOffer = rdpgfx_process_cache_import_offer_pdu;
1864 context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu;
1865 context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu;
1866 context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu;
1867 context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu;
1868 context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu;
1869 context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu;
1870 context->CapsAdvertise = nullptr;
1871 context->CapsConfirm = rdpgfx_send_caps_confirm_pdu;
1872 context->FrameAcknowledge = nullptr;
1873 context->QoeFrameAcknowledge = nullptr;
1874 RdpgfxServerPrivate* priv = context->priv =
1875 (RdpgfxServerPrivate*)calloc(1, sizeof(RdpgfxServerPrivate));
1876
1877 if (!priv)
1878 goto fail;
1879
1880 priv->log = WLog_Get(TAG);
1881 if (!priv->log)
1882 goto fail;
1883
1884 /* Create shared input stream */
1885 priv->input_stream = Stream_New(nullptr, 4);
1886
1887 if (!priv->input_stream)
1888 {
1889 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
1890 goto fail;
1891 }
1892
1893 priv->isOpened = FALSE;
1894 priv->isReady = FALSE;
1895 priv->ownThread = TRUE;
1896
1897 {
1898 const RDPGFX_CAPSET empty = WINPR_C_ARRAY_INIT;
1899 priv->activeCapSet = empty;
1900 }
1901
1902 return context;
1903fail:
1904 WINPR_PRAGMA_DIAG_PUSH
1905 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1906 rdpgfx_server_context_free(context);
1907 WINPR_PRAGMA_DIAG_POP
1908 return nullptr;
1909}
1910
1911void rdpgfx_server_context_free(RdpgfxServerContext* context)
1912{
1913 if (!context)
1914 return;
1915
1916 (void)rdpgfx_server_close(context);
1917
1918 if (context->priv)
1919 Stream_Free(context->priv->input_stream, TRUE);
1920
1921 free(context->priv);
1922 free(context);
1923}
1924
1925HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context)
1926{
1927 if (!context)
1928 return nullptr;
1929 if (!context->priv)
1930 return nullptr;
1931 return context->priv->channelEvent;
1932}
1933
1934/*
1935 * Handle rpdgfx messages - server side
1936 *
1937 * @param context side context
1938 *
1939 * @return 0 on success
1940 * ERROR_NO_DATA if no data could be read this time
1941 * otherwise a Win32 error code
1942 */
1943UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
1944{
1945 DWORD BytesReturned = 0;
1946 void* buffer = nullptr;
1947 UINT ret = CHANNEL_RC_OK;
1948
1949 WINPR_ASSERT(context);
1950 WINPR_ASSERT(context->priv);
1951
1952 RdpgfxServerPrivate* priv = context->priv;
1953 wStream* s = priv->input_stream;
1954
1955 /* Check whether the dynamic channel is ready */
1956 if (!priv->isReady)
1957 {
1958 if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer,
1959 &BytesReturned) == FALSE)
1960 {
1961 if (GetLastError() == ERROR_NO_DATA)
1962 return ERROR_NO_DATA;
1963
1964 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
1965 return ERROR_INTERNAL_ERROR;
1966 }
1967
1968 priv->isReady = *((BOOL*)buffer);
1969 WTSFreeMemory(buffer);
1970 }
1971
1972 /* Consume channel event only after the gfx dynamic channel is ready */
1973 if (priv->isReady)
1974 {
1975 Stream_ResetPosition(s);
1976
1977 if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, nullptr, 0, &BytesReturned))
1978 {
1979 if (GetLastError() == ERROR_NO_DATA)
1980 return ERROR_NO_DATA;
1981
1982 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
1983 return ERROR_INTERNAL_ERROR;
1984 }
1985
1986 if (BytesReturned < 1)
1987 return CHANNEL_RC_OK;
1988
1989 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
1990 {
1991 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
1992 return CHANNEL_RC_NO_MEMORY;
1993 }
1994
1995 const size_t len = Stream_Capacity(s);
1996 if (len > UINT32_MAX)
1997 return ERROR_INTERNAL_ERROR;
1998 if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, Stream_BufferAs(s, char), (UINT32)len,
1999 &BytesReturned) == FALSE)
2000 {
2001 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
2002 return ERROR_INTERNAL_ERROR;
2003 }
2004
2005 if (!Stream_SetLength(s, BytesReturned))
2006 return ERROR_INTERNAL_ERROR;
2007
2008 Stream_ResetPosition(s);
2009
2010 while (Stream_GetPosition(s) < Stream_Length(s))
2011 {
2012 if ((ret = rdpgfx_server_receive_pdu(context, s)))
2013 {
2014 WLog_Print(context->priv->log, WLOG_ERROR,
2015 "rdpgfx_server_receive_pdu "
2016 "failed with error %" PRIu32 "!",
2017 ret);
2018 return ret;
2019 }
2020 }
2021 }
2022
2023 return ret;
2024}