FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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#define RDPGFX_RESET_GRAPHICS_PDU_SIZE 340
44
45#define checkCapsAreExchanged(context) \
46 checkCapsAreExchangedInt(context, __FILE__, __func__, __LINE__)
47static BOOL checkCapsAreExchangedInt(RdpgfxServerContext* context, const char* file,
48 const char* fkt, size_t line)
49{
50 WINPR_ASSERT(context);
51 WINPR_ASSERT(context->priv);
52
53 const DWORD level = WLOG_TRACE;
54 if (WLog_IsLevelActive(context->priv->log, level))
55 {
56 WLog_PrintMessage(context->priv->log, WLOG_MESSAGE_TEXT, level, line, file, fkt,
57 "activeCapSet{Version=0x%08" PRIx32 ", flags=0x%08" PRIx32 "}",
58 context->priv->activeCapSet.version, context->priv->activeCapSet.flags);
59 }
60 return context->priv->activeCapSet.version > 0;
61}
62
72static INLINE UINT32 rdpgfx_pdu_length(UINT32 dataLen)
73{
74 return RDPGFX_HEADER_SIZE + dataLen;
75}
76
77static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, UINT16 cmdId, UINT32 pduLength)
78{
79 RDPGFX_HEADER header;
80 header.flags = 0;
81 header.cmdId = cmdId;
82 header.pduLength = pduLength;
83 /* Write header. Note that actual length might be changed
84 * after the entire packet has been constructed. */
85 return rdpgfx_write_header(s, &header);
86}
87
95static INLINE BOOL rdpgfx_server_packet_complete_header(wStream* s, size_t start)
96{
97 const size_t current = Stream_GetPosition(s);
98 const size_t cap = Stream_Capacity(s);
99 if (cap < start + RDPGFX_HEADER_SIZE)
100 return FALSE;
101 if ((start > UINT32_MAX) || (current < start))
102 return FALSE;
103 /* Fill actual length */
104 Stream_SetPosition(s, start + RDPGFX_HEADER_SIZE - sizeof(UINT32));
105 Stream_Write_UINT32(s, (UINT32)(current - start)); /* pduLength (4 bytes) */
106 Stream_SetPosition(s, current);
107 return TRUE;
108}
109
117static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s)
118{
119 UINT error = 0;
120 UINT32 flags = 0;
121 ULONG written = 0;
122 BYTE* pSrcData = Stream_Buffer(s);
123 const size_t SrcSize = Stream_GetPosition(s);
124 if (SrcSize > UINT32_MAX)
125 return ERROR_INTERNAL_ERROR;
126
127 wStream* fs = NULL;
128 /* Allocate new stream with enough capacity. Additional overhead is
129 * descriptor (1 bytes) + segmentCount (2 bytes) + uncompressedSize (4 bytes)
130 * + segmentCount * size (4 bytes) */
131 fs = Stream_New(NULL, SrcSize + 7 + (SrcSize / ZGFX_SEGMENTED_MAXSIZE + 1) * 4);
132
133 if (!fs)
134 {
135 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
136 error = CHANNEL_RC_NO_MEMORY;
137 goto out;
138 }
139
140 if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, (UINT32)SrcSize, &flags) < 0)
141 {
142 WLog_Print(context->priv->log, WLOG_ERROR, "zgfx_compress_to_stream failed!");
143 error = ERROR_INTERNAL_ERROR;
144 goto out;
145 }
146
147 const size_t pos = Stream_GetPosition(fs);
148
149 WINPR_ASSERT(pos <= UINT32_MAX);
150 if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, Stream_BufferAs(fs, char),
151 (UINT32)pos, &written))
152 {
153 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelWrite failed!");
154 error = ERROR_INTERNAL_ERROR;
155 goto out;
156 }
157
158 if (written < Stream_GetPosition(fs))
159 {
160 WLog_Print(context->priv->log, WLOG_WARN,
161 "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
162 Stream_GetPosition(fs));
163 }
164
165 error = CHANNEL_RC_OK;
166out:
167 Stream_Free(fs, TRUE);
168 Stream_Free(s, TRUE);
169 return error;
170}
171
184static wStream* rdpgfx_server_single_packet_new(wLog* log, UINT16 cmdId, UINT32 dataLen)
185{
186 UINT error = 0;
187 wStream* s = NULL;
188 UINT32 pduLength = rdpgfx_pdu_length(dataLen);
189 s = Stream_New(NULL, pduLength);
190
191 if (!s)
192 {
193 WLog_Print(log, WLOG_ERROR, "Stream_New failed!");
194 goto error;
195 }
196
197 if ((error = rdpgfx_server_packet_init_header(s, cmdId, pduLength)))
198 {
199 WLog_Print(log, WLOG_ERROR, "Failed to init header with error %" PRIu32 "!", error);
200 goto error;
201 }
202
203 return s;
204error:
205 Stream_Free(s, TRUE);
206 return NULL;
207}
208
217static INLINE UINT rdpgfx_server_single_packet_send(RdpgfxServerContext* context, wStream* s)
218{
219 /* Fill actual length */
220 rdpgfx_server_packet_complete_header(s, 0);
221 return rdpgfx_server_packet_send(context, s);
222}
223
229static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context,
230 const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm)
231{
232 wStream* s = NULL;
233 RDPGFX_CAPSET* capsSet = NULL;
234
235 WINPR_ASSERT(context);
236 WINPR_ASSERT(capsConfirm);
237
238 capsSet = capsConfirm->capsSet;
239 WINPR_ASSERT(capsSet);
240
241 s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CAPSCONFIRM,
242 RDPGFX_CAPSET_BASE_SIZE + capsSet->length);
243
244 if (!s)
245 {
246 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
247 return CHANNEL_RC_NO_MEMORY;
248 }
249
250 WLog_DBG(TAG, "CAPS version=0x%04" PRIx32 ", flags=0x%04" PRIx32 ", length=%" PRIu32,
251 capsSet->version, capsSet->flags, capsSet->length);
252 Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */
253 Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
254
255 if (capsSet->length >= 4)
256 {
257 Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
258 Stream_Zero(s, capsSet->length - 4);
259 }
260 else
261 Stream_Zero(s, capsSet->length);
262
263 context->priv->activeCapSet = *capsSet;
264 return rdpgfx_server_single_packet_send(context, s);
265}
266
272static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context,
273 const RDPGFX_RESET_GRAPHICS_PDU* pdu)
274{
275 if (!checkCapsAreExchanged(context))
276 return CHANNEL_RC_NOT_INITIALIZED;
277
278 wStream* s = NULL;
279
280 /* Check monitorCount. This ensures total size within 340 bytes) */
281 if (pdu->monitorCount >= 16)
282 {
283 WLog_Print(context->priv->log, WLOG_ERROR,
284 "Monitor count MUST be less than or equal to 16: %" PRIu32 "",
285 pdu->monitorCount);
286 return ERROR_INVALID_DATA;
287 }
288
289 s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_RESETGRAPHICS,
290 RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE);
291
292 if (!s)
293 {
294 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
295 return CHANNEL_RC_NO_MEMORY;
296 }
297
298 Stream_Write_UINT32(s, pdu->width); /* width (4 bytes) */
299 Stream_Write_UINT32(s, pdu->height); /* height (4 bytes) */
300 Stream_Write_UINT32(s, pdu->monitorCount); /* monitorCount (4 bytes) */
301
302 for (UINT32 index = 0; index < pdu->monitorCount; index++)
303 {
304 const MONITOR_DEF* monitor = &(pdu->monitorDefArray[index]);
305 Stream_Write_INT32(s, monitor->left); /* left (4 bytes) */
306 Stream_Write_INT32(s, monitor->top); /* top (4 bytes) */
307 Stream_Write_INT32(s, monitor->right); /* right (4 bytes) */
308 Stream_Write_INT32(s, monitor->bottom); /* bottom (4 bytes) */
309 Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */
310 }
311
312 /* pad (total size must be 340 bytes) */
313 Stream_SetPosition(s, RDPGFX_RESET_GRAPHICS_PDU_SIZE);
314 return rdpgfx_server_single_packet_send(context, s);
315}
316
322static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context,
324{
325 if (!checkCapsAreExchanged(context))
326 return CHANNEL_RC_NOT_INITIALIZED;
327 wStream* s =
328 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_EVICTCACHEENTRY, 2);
329
330 if (!s)
331 {
332 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
333 return CHANNEL_RC_NO_MEMORY;
334 }
335
336 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
337 return rdpgfx_server_single_packet_send(context, s);
338}
339
345static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context,
347{
348 if (!checkCapsAreExchanged(context))
349 return CHANNEL_RC_NOT_INITIALIZED;
350 WINPR_ASSERT(context);
351 WINPR_ASSERT(pdu);
352
353 WLog_DBG(TAG, "reply with %" PRIu16 " entries", pdu->importedEntriesCount);
354 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHEIMPORTREPLY,
355 2 + 2 * pdu->importedEntriesCount);
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 /* importedEntriesCount (2 bytes) */
364 Stream_Write_UINT16(s, pdu->importedEntriesCount);
365
366 for (UINT16 index = 0; index < pdu->importedEntriesCount; index++)
367 {
368 Stream_Write_UINT16(s, pdu->cacheSlots[index]); /* cacheSlot (2 bytes) */
369 }
370
371 return rdpgfx_server_single_packet_send(context, s);
372}
373
374static UINT
375rdpgfx_process_cache_import_offer_pdu(RdpgfxServerContext* context,
376 const RDPGFX_CACHE_IMPORT_OFFER_PDU* cacheImportOffer)
377{
378 if (!checkCapsAreExchanged(context))
379 return CHANNEL_RC_NOT_INITIALIZED;
380 WINPR_ASSERT(context);
381 WINPR_ASSERT(cacheImportOffer);
382
383 RDPGFX_CACHE_IMPORT_REPLY_PDU reply = { 0 };
384 WLog_DBG(TAG, "received %" PRIu16 " entries, reply with %" PRIu16 " entries",
385 cacheImportOffer->cacheEntriesCount, reply.importedEntriesCount);
386 return IFCALLRESULT(CHANNEL_RC_OK, context->CacheImportReply, context, &reply);
387}
388
394static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context,
395 const RDPGFX_CREATE_SURFACE_PDU* pdu)
396{
397 if (!checkCapsAreExchanged(context))
398 return CHANNEL_RC_NOT_INITIALIZED;
399 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CREATESURFACE, 7);
400
401 WINPR_ASSERT(context);
402 WINPR_ASSERT(pdu);
403 WINPR_ASSERT((pdu->pixelFormat == GFX_PIXEL_FORMAT_XRGB_8888) ||
404 (pdu->pixelFormat == GFX_PIXEL_FORMAT_ARGB_8888));
405
406 if (!s)
407 {
408 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
409 return CHANNEL_RC_NO_MEMORY;
410 }
411
412 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
413 Stream_Write_UINT16(s, pdu->width); /* width (2 bytes) */
414 Stream_Write_UINT16(s, pdu->height); /* height (2 bytes) */
415 Stream_Write_UINT8(s, pdu->pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */
416 return rdpgfx_server_single_packet_send(context, s);
417}
418
424static UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context,
425 const RDPGFX_DELETE_SURFACE_PDU* pdu)
426{
427 if (!checkCapsAreExchanged(context))
428 return CHANNEL_RC_NOT_INITIALIZED;
429 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETESURFACE, 2);
430
431 if (!s)
432 {
433 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
434 return CHANNEL_RC_NO_MEMORY;
435 }
436
437 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
438 return rdpgfx_server_single_packet_send(context, s);
439}
440
441static INLINE BOOL rdpgfx_write_start_frame_pdu(wStream* s, const RDPGFX_START_FRAME_PDU* pdu)
442{
443 if (!Stream_EnsureRemainingCapacity(s, 8))
444 return FALSE;
445 Stream_Write_UINT32(s, pdu->timestamp); /* timestamp (4 bytes) */
446 Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
447 return TRUE;
448}
449
450static INLINE BOOL rdpgfx_write_end_frame_pdu(wStream* s, const RDPGFX_END_FRAME_PDU* pdu)
451{
452 if (!Stream_EnsureRemainingCapacity(s, 4))
453 return FALSE;
454 Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
455 return TRUE;
456}
457
463static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context,
464 const RDPGFX_START_FRAME_PDU* pdu)
465{
466 if (!checkCapsAreExchanged(context))
467 return CHANNEL_RC_NOT_INITIALIZED;
468 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_STARTFRAME,
469 RDPGFX_START_FRAME_PDU_SIZE);
470
471 if (!s)
472 {
473 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
474 return CHANNEL_RC_NO_MEMORY;
475 }
476
477 rdpgfx_write_start_frame_pdu(s, pdu);
478 return rdpgfx_server_single_packet_send(context, s);
479}
480
486static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, const RDPGFX_END_FRAME_PDU* pdu)
487{
488 if (!checkCapsAreExchanged(context))
489 return CHANNEL_RC_NOT_INITIALIZED;
490 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_ENDFRAME,
491 RDPGFX_END_FRAME_PDU_SIZE);
492
493 if (!s)
494 {
495 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
496 return CHANNEL_RC_NO_MEMORY;
497 }
498
499 rdpgfx_write_end_frame_pdu(s, pdu);
500 return rdpgfx_server_single_packet_send(context, s);
501}
502
509static INLINE UINT32 rdpgfx_estimate_h264_avc420(const RDPGFX_AVC420_BITMAP_STREAM* havc420)
510{
511 /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
512 return sizeof(UINT32) /* numRegionRects */
513 + 10ULL /* regionRects + quantQualityVals */
514 * havc420->meta.numRegionRects +
515 havc420->length;
516}
517
524static INLINE UINT32 rdpgfx_estimate_surface_command(const RDPGFX_SURFACE_COMMAND* cmd)
525{
526 RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL;
527 RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL;
528 UINT32 h264Size = 0;
529
530 /* Estimate stream size according to codec. */
531 switch (cmd->codecId)
532 {
533 case RDPGFX_CODECID_CAPROGRESSIVE:
534 case RDPGFX_CODECID_CAPROGRESSIVE_V2:
535 return RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE + cmd->length;
536
537 case RDPGFX_CODECID_AVC420:
538 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
539 h264Size = rdpgfx_estimate_h264_avc420(havc420);
540 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
541
542 case RDPGFX_CODECID_AVC444:
543 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
544 h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */
545 /* avc420EncodedBitstream1 */
546 havc420 = &(havc444->bitstream[0]);
547 h264Size += rdpgfx_estimate_h264_avc420(havc420);
548
549 /* avc420EncodedBitstream2 */
550 if (havc444->LC == 0)
551 {
552 havc420 = &(havc444->bitstream[1]);
553 h264Size += rdpgfx_estimate_h264_avc420(havc420);
554 }
555
556 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
557
558 default:
559 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + cmd->length;
560 }
561}
562
570static INLINE UINT16 rdpgfx_surface_command_cmdid(const RDPGFX_SURFACE_COMMAND* cmd)
571{
572 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
573 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
574 {
575 return RDPGFX_CMDID_WIRETOSURFACE_2;
576 }
577
578 return RDPGFX_CMDID_WIRETOSURFACE_1;
579}
580
586static UINT rdpgfx_write_h264_metablock(wLog* log, wStream* s, const RDPGFX_H264_METABLOCK* meta)
587{
588 RECTANGLE_16* regionRect = NULL;
589 RDPGFX_H264_QUANT_QUALITY* quantQualityVal = NULL;
590 UINT error = CHANNEL_RC_OK;
591
592 if (!Stream_EnsureRemainingCapacity(s, 4 + meta->numRegionRects * 10))
593 return ERROR_OUTOFMEMORY;
594
595 Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
596
597 for (UINT32 index = 0; index < meta->numRegionRects; index++)
598 {
599 regionRect = &(meta->regionRects[index]);
600
601 if ((error = rdpgfx_write_rect16(s, regionRect)))
602 {
603 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_rect16 failed with error %" PRIu32 "!",
604 error);
605 return error;
606 }
607 }
608
609 for (UINT32 index = 0; index < meta->numRegionRects; index++)
610 {
611 quantQualityVal = &(meta->quantQualityVals[index]);
612 Stream_Write_UINT8(s, WINPR_ASSERTING_INT_CAST(
613 uint8_t, quantQualityVal->qp | (quantQualityVal->r << 6) |
614 (quantQualityVal->p << 7))); /* qpVal (1 byte) */
615 /* qualityVal (1 byte) */
616 Stream_Write_UINT8(s, quantQualityVal->qualityVal);
617 }
618
619 return error;
620}
621
628static INLINE UINT rdpgfx_write_h264_avc420(wLog* log, wStream* s,
630{
631 UINT error = CHANNEL_RC_OK;
632
633 if ((error = rdpgfx_write_h264_metablock(log, s, &(havc420->meta))))
634 {
635 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_metablock failed with error %" PRIu32 "!",
636 error);
637 return error;
638 }
639
640 if (!Stream_EnsureRemainingCapacity(s, havc420->length))
641 return ERROR_OUTOFMEMORY;
642
643 Stream_Write(s, havc420->data, havc420->length);
644 return error;
645}
646
654static UINT rdpgfx_write_surface_command(wLog* log, wStream* s, const RDPGFX_SURFACE_COMMAND* cmd)
655{
656 UINT error = CHANNEL_RC_OK;
657 RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL;
658 RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL;
659 UINT8 pixelFormat = 0;
660
661 switch (cmd->format)
662 {
663 case PIXEL_FORMAT_BGRX32:
664 pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
665 break;
666
667 case PIXEL_FORMAT_BGRA32:
668 pixelFormat = GFX_PIXEL_FORMAT_ARGB_8888;
669 break;
670
671 default:
672 WLog_Print(log, WLOG_ERROR, "Format %s not supported!",
673 FreeRDPGetColorFormatName(cmd->format));
674 return ERROR_INVALID_DATA;
675 }
676
677 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
678 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
679 {
680 if (!Stream_EnsureRemainingCapacity(s, 13 + cmd->length))
681 return ERROR_INTERNAL_ERROR;
682 /* Write RDPGFX_CMDID_WIRETOSURFACE_2 format for CAPROGRESSIVE */
683 Stream_Write_UINT16(
684 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->surfaceId)); /* surfaceId (2 bytes) */
685 Stream_Write_UINT16(
686 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->codecId)); /* codecId (2 bytes) */
687 Stream_Write_UINT32(s, cmd->contextId); /* codecContextId (4 bytes) */
688 Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */
689 Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */
690 Stream_Write(s, cmd->data, cmd->length);
691 }
692 else
693 {
694 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 format for others */
695 if (!Stream_EnsureRemainingCapacity(s, 17))
696 return ERROR_INTERNAL_ERROR;
697 Stream_Write_UINT16(
698 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->surfaceId)); /* surfaceId (2 bytes) */
699 Stream_Write_UINT16(
700 s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->codecId)); /* codecId (2 bytes) */
701 Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */
702 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->left)); /* left (2 bytes) */
703 Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->top)); /* top (2 bytes) */
704 Stream_Write_UINT16(s,
705 WINPR_ASSERTING_INT_CAST(uint16_t, cmd->right)); /* right (2 bytes) */
706 Stream_Write_UINT16(s,
707 WINPR_ASSERTING_INT_CAST(uint16_t, cmd->bottom)); /* bottom (2 bytes) */
708 Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */
709 const size_t bitmapDataStart = Stream_GetPosition(s);
710
711 if (cmd->codecId == RDPGFX_CODECID_AVC420)
712 {
713 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
714 error = rdpgfx_write_h264_avc420(log, s, havc420);
715
716 if (error != CHANNEL_RC_OK)
717 {
718 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
719 return error;
720 }
721 }
722 else if ((cmd->codecId == RDPGFX_CODECID_AVC444) ||
723 (cmd->codecId == RDPGFX_CODECID_AVC444v2))
724 {
725 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
726 havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */
727 if (!Stream_EnsureRemainingCapacity(s, 4))
728 return ERROR_INTERNAL_ERROR;
729 Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 |
730 ((uint32_t)havc444->LC << 30UL));
731 /* avc420EncodedBitstream1 */
732 error = rdpgfx_write_h264_avc420(log, s, havc420);
733
734 if (error != CHANNEL_RC_OK)
735 {
736 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
737 return error;
738 }
739
740 /* avc420EncodedBitstream2 */
741 if (havc444->LC == 0)
742 {
743 havc420 = &(havc444->bitstream[1]);
744 error = rdpgfx_write_h264_avc420(log, s, havc420);
745
746 if (error != CHANNEL_RC_OK)
747 {
748 WLog_Print(log, WLOG_ERROR, "rdpgfx_write_h264_avc420 failed!");
749 return error;
750 }
751 }
752 }
753 else
754 {
755 if (!Stream_EnsureRemainingCapacity(s, cmd->length))
756 return ERROR_INTERNAL_ERROR;
757 Stream_Write(s, cmd->data, cmd->length);
758 }
759
760 /* Fill actual bitmap data length */
761 const size_t bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart;
762 if (bitmapDataLength > UINT32_MAX)
763 return ERROR_INTERNAL_ERROR;
764
765 Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32));
766 if (!Stream_EnsureRemainingCapacity(s, 4))
767 return ERROR_INTERNAL_ERROR;
768 Stream_Write_UINT32(s, (UINT32)bitmapDataLength); /* bitmapDataLength (4 bytes) */
769 if (!Stream_SafeSeek(s, bitmapDataLength))
770 return ERROR_INTERNAL_ERROR;
771 }
772
773 return error;
774}
775
783static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context,
784 const RDPGFX_SURFACE_COMMAND* cmd)
785{
786 if (!checkCapsAreExchanged(context))
787 return CHANNEL_RC_NOT_INITIALIZED;
788 UINT error = CHANNEL_RC_OK;
789 wStream* s = NULL;
790 s = rdpgfx_server_single_packet_new(context->priv->log, rdpgfx_surface_command_cmdid(cmd),
791 rdpgfx_estimate_surface_command(cmd));
792
793 if (!s)
794 {
795 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
796 return CHANNEL_RC_NO_MEMORY;
797 }
798
799 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
800
801 if (error != CHANNEL_RC_OK)
802 {
803 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
804 goto error;
805 }
806
807 return rdpgfx_server_single_packet_send(context, s);
808error:
809 Stream_Free(s, TRUE);
810 return error;
811}
812
821static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context,
822 const RDPGFX_SURFACE_COMMAND* cmd,
823 const RDPGFX_START_FRAME_PDU* startFrame,
824 const RDPGFX_END_FRAME_PDU* endFrame)
825
826{
827 if (!checkCapsAreExchanged(context))
828 return CHANNEL_RC_NOT_INITIALIZED;
829 UINT error = CHANNEL_RC_OK;
830 UINT32 size = rdpgfx_pdu_length(rdpgfx_estimate_surface_command(cmd));
831
832 if (startFrame)
833 {
834 size += rdpgfx_pdu_length(RDPGFX_START_FRAME_PDU_SIZE);
835 }
836
837 if (endFrame)
838 {
839 size += rdpgfx_pdu_length(RDPGFX_END_FRAME_PDU_SIZE);
840 }
841
842 wStream* s = Stream_New(NULL, size);
843
844 if (!s)
845 {
846 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
847 return CHANNEL_RC_NO_MEMORY;
848 }
849
850 /* Write start frame if exists */
851 if (startFrame)
852 {
853 const size_t position = Stream_GetPosition(s);
854 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_STARTFRAME, 0);
855
856 if (error != CHANNEL_RC_OK)
857 {
858 WLog_Print(context->priv->log, WLOG_ERROR,
859 "Failed to init header with error %" PRIu32 "!", error);
860 goto error;
861 }
862
863 if (!rdpgfx_write_start_frame_pdu(s, startFrame) ||
864 !rdpgfx_server_packet_complete_header(s, position))
865 goto error;
866 }
867
868 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */
869 const size_t pos = Stream_GetPosition(s);
870 error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd),
871 0); // Actual length will be filled later
872
873 if (error != CHANNEL_RC_OK)
874 {
875 WLog_Print(context->priv->log, WLOG_ERROR, "Failed to init header with error %" PRIu32 "!",
876 error);
877 goto error;
878 }
879
880 error = rdpgfx_write_surface_command(context->priv->log, s, cmd);
881
882 if (error != CHANNEL_RC_OK)
883 {
884 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_write_surface_command failed!");
885 goto error;
886 }
887
888 if (!rdpgfx_server_packet_complete_header(s, pos))
889 goto error;
890
891 /* Write end frame if exists */
892 if (endFrame)
893 {
894 const size_t position = Stream_GetPosition(s);
895 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0);
896
897 if (error != CHANNEL_RC_OK)
898 {
899 WLog_Print(context->priv->log, WLOG_ERROR,
900 "Failed to init header with error %" PRIu32 "!", error);
901 goto error;
902 }
903
904 if (!rdpgfx_write_end_frame_pdu(s, endFrame) ||
905 !rdpgfx_server_packet_complete_header(s, position))
906 goto error;
907 }
908
909 return rdpgfx_server_packet_send(context, s);
910error:
911 Stream_Free(s, TRUE);
912 return error;
913}
914
920static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context,
922{
923 if (!checkCapsAreExchanged(context))
924 return CHANNEL_RC_NOT_INITIALIZED;
925 wStream* s =
926 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6);
927
928 if (!s)
929 {
930 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
931 return CHANNEL_RC_NO_MEMORY;
932 }
933
934 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
935 Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */
936 return rdpgfx_server_single_packet_send(context, s);
937}
938
944static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context,
945 const RDPGFX_SOLID_FILL_PDU* pdu)
946{
947 if (!checkCapsAreExchanged(context))
948 return CHANNEL_RC_NOT_INITIALIZED;
949 UINT error = CHANNEL_RC_OK;
950 RECTANGLE_16* fillRect = NULL;
951 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SOLIDFILL,
952 8 + 8 * pdu->fillRectCount);
953
954 if (!s)
955 {
956 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
957 return CHANNEL_RC_NO_MEMORY;
958 }
959
960 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
961
962 /* fillPixel (4 bytes) */
963 if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel))))
964 {
965 WLog_Print(context->priv->log, WLOG_ERROR,
966 "rdpgfx_write_color32 failed with error %" PRIu32 "!", error);
967 goto error;
968 }
969
970 Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */
971
972 for (UINT16 index = 0; index < pdu->fillRectCount; index++)
973 {
974 fillRect = &(pdu->fillRects[index]);
975
976 if ((error = rdpgfx_write_rect16(s, fillRect)))
977 {
978 WLog_Print(context->priv->log, WLOG_ERROR,
979 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
980 goto error;
981 }
982 }
983
984 return rdpgfx_server_single_packet_send(context, s);
985error:
986 Stream_Free(s, TRUE);
987 return error;
988}
989
995static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context,
997{
998 if (!checkCapsAreExchanged(context))
999 return CHANNEL_RC_NOT_INITIALIZED;
1000 UINT error = CHANNEL_RC_OK;
1001 RDPGFX_POINT16* destPt = NULL;
1002 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOSURFACE,
1003 14 + 4 * pdu->destPtsCount);
1004
1005 if (!s)
1006 {
1007 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1008 return CHANNEL_RC_NO_MEMORY;
1009 }
1010
1011 Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
1012 Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */
1013
1014 /* rectSrc (8 bytes ) */
1015 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1016 {
1017 WLog_Print(context->priv->log, WLOG_ERROR,
1018 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1019 goto error;
1020 }
1021
1022 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1023
1024 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1025 {
1026 destPt = &(pdu->destPts[index]);
1027
1028 if ((error = rdpgfx_write_point16(s, destPt)))
1029 {
1030 WLog_Print(context->priv->log, WLOG_ERROR,
1031 "rdpgfx_write_point16 failed with error %" PRIu32 "!", error);
1032 goto error;
1033 }
1034 }
1035
1036 return rdpgfx_server_single_packet_send(context, s);
1037error:
1038 Stream_Free(s, TRUE);
1039 return error;
1040}
1041
1047static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context,
1048 const RDPGFX_SURFACE_TO_CACHE_PDU* pdu)
1049{
1050 if (!checkCapsAreExchanged(context))
1051 return CHANNEL_RC_NOT_INITIALIZED;
1052 UINT error = CHANNEL_RC_OK;
1053 wStream* s =
1054 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_SURFACETOCACHE, 20);
1055
1056 if (!s)
1057 {
1058 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1059 return CHANNEL_RC_NO_MEMORY;
1060 }
1061
1062 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1063 Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */
1064 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1065
1066 /* rectSrc (8 bytes ) */
1067 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
1068 {
1069 WLog_Print(context->priv->log, WLOG_ERROR,
1070 "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
1071 goto error;
1072 }
1073
1074 return rdpgfx_server_single_packet_send(context, s);
1075error:
1076 Stream_Free(s, TRUE);
1077 return error;
1078}
1079
1085static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context,
1086 const RDPGFX_CACHE_TO_SURFACE_PDU* pdu)
1087{
1088 if (!checkCapsAreExchanged(context))
1089 return CHANNEL_RC_NOT_INITIALIZED;
1090 UINT error = CHANNEL_RC_OK;
1091 RDPGFX_POINT16* destPt = NULL;
1092 wStream* s = rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_CACHETOSURFACE,
1093 6 + 4 * pdu->destPtsCount);
1094
1095 if (!s)
1096 {
1097 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1098 return CHANNEL_RC_NO_MEMORY;
1099 }
1100
1101 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
1102 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1103 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
1104
1105 for (UINT16 index = 0; index < pdu->destPtsCount; index++)
1106 {
1107 destPt = &(pdu->destPts[index]);
1108
1109 if ((error = rdpgfx_write_point16(s, destPt)))
1110 {
1111 WLog_Print(context->priv->log, WLOG_ERROR,
1112 "rdpgfx_write_point16 failed with error %" PRIu32 "", error);
1113 goto error;
1114 }
1115 }
1116
1117 return rdpgfx_server_single_packet_send(context, s);
1118error:
1119 Stream_Free(s, TRUE);
1120 return error;
1121}
1122
1128static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context,
1130{
1131 if (!checkCapsAreExchanged(context))
1132 return CHANNEL_RC_NOT_INITIALIZED;
1133 wStream* s =
1134 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12);
1135
1136 if (!s)
1137 {
1138 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1139 return CHANNEL_RC_NO_MEMORY;
1140 }
1141
1142 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1143 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1144 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1145 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1146 return rdpgfx_server_single_packet_send(context, s);
1147}
1148
1154static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context,
1156{
1157 if (!checkCapsAreExchanged(context))
1158 return CHANNEL_RC_NOT_INITIALIZED;
1159 wStream* s =
1160 rdpgfx_server_single_packet_new(context->priv->log, RDPGFX_CMDID_MAPSURFACETOWINDOW, 18);
1161
1162 if (!s)
1163 {
1164 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1165 return CHANNEL_RC_NO_MEMORY;
1166 }
1167
1168 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1169 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1170 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1171 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1172 return rdpgfx_server_single_packet_send(context, s);
1173}
1174
1175static UINT
1176rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context,
1178{
1179 if (!checkCapsAreExchanged(context))
1180 return CHANNEL_RC_NOT_INITIALIZED;
1181 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1182 RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26);
1183
1184 if (!s)
1185 {
1186 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1187 return CHANNEL_RC_NO_MEMORY;
1188 }
1189
1190 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1191 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1192 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1193 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1194 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1195 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1196 return rdpgfx_server_single_packet_send(context, s);
1197}
1198
1204static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s)
1205{
1206 if (!checkCapsAreExchanged(context))
1207 return CHANNEL_RC_NOT_INITIALIZED;
1209 UINT error = CHANNEL_RC_OK;
1210
1211 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
1212 return ERROR_INVALID_DATA;
1213
1214 Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */
1215 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1216 Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
1217
1218 if (context)
1219 {
1220 IFCALLRET(context->FrameAcknowledge, error, context, &pdu);
1221
1222 if (error)
1223 WLog_Print(context->priv->log, WLOG_ERROR,
1224 "context->FrameAcknowledge failed with error %" PRIu32 "", error);
1225 }
1226
1227 return error;
1228}
1229
1235static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wStream* s)
1236{
1237 if (!checkCapsAreExchanged(context))
1238 return CHANNEL_RC_NOT_INITIALIZED;
1239
1241 RDPGFX_CACHE_ENTRY_METADATA* cacheEntry = NULL;
1242 UINT error = CHANNEL_RC_OK;
1243
1244 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1245 return ERROR_INVALID_DATA;
1246
1247 /* cacheEntriesCount (2 bytes) */
1248 Stream_Read_UINT16(s, pdu.cacheEntriesCount);
1249
1250 /* 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU */
1251 if (pdu.cacheEntriesCount >= 5462)
1252 {
1253 WLog_Print(context->priv->log, WLOG_ERROR, "Invalid cacheEntriesCount: %" PRIu16 "",
1254 pdu.cacheEntriesCount);
1255 return ERROR_INVALID_DATA;
1256 }
1257
1258 if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, pdu.cacheEntriesCount, 12ull))
1259 return ERROR_INVALID_DATA;
1260
1261 for (UINT16 index = 0; index < pdu.cacheEntriesCount; index++)
1262 {
1263 cacheEntry = &(pdu.cacheEntries[index]);
1264 Stream_Read_UINT64(s, cacheEntry->cacheKey); /* cacheKey (8 bytes) */
1265 Stream_Read_UINT32(s, cacheEntry->bitmapLength); /* bitmapLength (4 bytes) */
1266 }
1267
1268 if (context)
1269 {
1270 IFCALLRET(context->CacheImportOffer, error, context, &pdu);
1271
1272 if (error)
1273 WLog_Print(context->priv->log, WLOG_ERROR,
1274 "context->CacheImportOffer failed with error %" PRIu32 "", error);
1275 }
1276
1277 return error;
1278}
1279
1285static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream* s)
1286{
1287 RDPGFX_CAPSET* capsSets = NULL;
1288 RDPGFX_CAPS_ADVERTISE_PDU pdu = { 0 };
1289 UINT error = ERROR_INVALID_DATA;
1290
1291 if (!context)
1292 return ERROR_BAD_ARGUMENTS;
1293
1294 if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
1295 return ERROR_INVALID_DATA;
1296
1297 Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
1298 if (pdu.capsSetCount > 0)
1299 {
1300 capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4));
1301 if (!capsSets)
1302 return ERROR_OUTOFMEMORY;
1303 }
1304
1305 pdu.capsSets = capsSets;
1306
1307 for (UINT16 index = 0; index < pdu.capsSetCount; index++)
1308 {
1309 RDPGFX_CAPSET* capsSet = &(pdu.capsSets[index]);
1310
1311 if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1312 goto fail;
1313
1314 Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */
1315 Stream_Read_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
1316
1317 if (capsSet->length >= 4)
1318 {
1319 if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1320 goto fail;
1321
1322 Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
1323 }
1324
1325 if (!Stream_SafeSeek(s, capsSet->length))
1326 goto fail;
1327 }
1328
1329 error = ERROR_BAD_CONFIGURATION;
1330 IFCALLRET(context->CapsAdvertise, error, context, &pdu);
1331
1332 if (error)
1333 WLog_Print(context->priv->log, WLOG_ERROR,
1334 "context->CapsAdvertise failed with error %" PRIu32 "", error);
1335
1336fail:
1337 free(capsSets);
1338 return error;
1339}
1340
1346static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s)
1347{
1348 if (!checkCapsAreExchanged(context))
1349 return CHANNEL_RC_NOT_INITIALIZED;
1351 UINT error = CHANNEL_RC_OK;
1352
1353 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
1354 return ERROR_INVALID_DATA;
1355
1356 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1357 Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
1358 Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */
1359 Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */
1360
1361 if (context)
1362 {
1363 IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu);
1364
1365 if (error)
1366 WLog_Print(context->priv->log, WLOG_ERROR,
1367 "context->QoeFrameAcknowledge failed with error %" PRIu32 "", error);
1368 }
1369
1370 return error;
1371}
1372
1373static UINT
1374rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context,
1376{
1377 if (!checkCapsAreExchanged(context))
1378 return CHANNEL_RC_NOT_INITIALIZED;
1379 wStream* s = rdpgfx_server_single_packet_new(context->priv->log,
1380 RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20);
1381
1382 if (!s)
1383 {
1384 WLog_Print(context->priv->log, WLOG_ERROR, "rdpgfx_server_single_packet_new failed!");
1385 return CHANNEL_RC_NO_MEMORY;
1386 }
1387
1388 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1389 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1390 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1391 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1392 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1393 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1394 return rdpgfx_server_single_packet_send(context, s);
1395}
1396
1402static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
1403{
1404 size_t beg = 0;
1405 size_t end = 0;
1406 RDPGFX_HEADER header;
1407 UINT error = CHANNEL_RC_OK;
1408 beg = Stream_GetPosition(s);
1409
1410 if ((error = rdpgfx_read_header(s, &header)))
1411 {
1412 WLog_Print(context->priv->log, WLOG_ERROR,
1413 "rdpgfx_read_header failed with error %" PRIu32 "!", error);
1414 return error;
1415 }
1416
1417#ifdef WITH_DEBUG_RDPGFX
1418 WLog_DBG(TAG, "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "",
1419 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength);
1420#endif
1421
1422 switch (header.cmdId)
1423 {
1424 case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
1425 if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
1426 WLog_Print(context->priv->log, WLOG_ERROR,
1427 "rdpgfx_recv_frame_acknowledge_pdu "
1428 "failed with error %" PRIu32 "!",
1429 error);
1430
1431 break;
1432
1433 case RDPGFX_CMDID_CACHEIMPORTOFFER:
1434 if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
1435 WLog_Print(context->priv->log, WLOG_ERROR,
1436 "rdpgfx_recv_cache_import_offer_pdu "
1437 "failed with error %" PRIu32 "!",
1438 error);
1439
1440 break;
1441
1442 case RDPGFX_CMDID_CAPSADVERTISE:
1443 if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
1444 WLog_Print(context->priv->log, WLOG_ERROR,
1445 "rdpgfx_recv_caps_advertise_pdu "
1446 "failed with error %" PRIu32 "!",
1447 error);
1448
1449 break;
1450
1451 case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
1452 if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
1453 WLog_Print(context->priv->log, WLOG_ERROR,
1454 "rdpgfx_recv_qoe_frame_acknowledge_pdu "
1455 "failed with error %" PRIu32 "!",
1456 error);
1457
1458 break;
1459
1460 default:
1461 error = CHANNEL_RC_BAD_PROC;
1462 break;
1463 }
1464
1465 if (error)
1466 {
1467 WLog_Print(context->priv->log, WLOG_ERROR,
1468 "Error while parsing GFX cmdId: %s (0x%04" PRIX16 ")",
1469 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
1470 return error;
1471 }
1472
1473 end = Stream_GetPosition(s);
1474
1475 if (end != (beg + header.pduLength))
1476 {
1477 WLog_Print(context->priv->log, WLOG_ERROR,
1478 "Unexpected gfx pdu end: Actual: %" PRIuz ", Expected: %" PRIuz "", end,
1479 (beg + header.pduLength));
1480 Stream_SetPosition(s, (beg + header.pduLength));
1481 }
1482
1483 return error;
1484}
1485
1486static BOOL rdpgfx_server_close(RdpgfxServerContext* context);
1487
1488static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
1489{
1490 RdpgfxServerContext* context = (RdpgfxServerContext*)arg;
1491 WINPR_ASSERT(context);
1492
1493 RdpgfxServerPrivate* priv = context->priv;
1494 DWORD status = 0;
1495 DWORD nCount = 0;
1496 HANDLE events[8] = { 0 };
1497 UINT error = CHANNEL_RC_OK;
1498
1499 WINPR_ASSERT(priv);
1500
1501 if (priv->ownThread)
1502 {
1503 WINPR_ASSERT(priv->stopEvent);
1504 events[nCount++] = priv->stopEvent;
1505 }
1506
1507 WINPR_ASSERT(priv->channelEvent);
1508 events[nCount++] = priv->channelEvent;
1509
1510 /* Main virtual channel loop. RDPGFX do not need version negotiation */
1511 while (TRUE)
1512 {
1513 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1514
1515 if (status == WAIT_FAILED)
1516 {
1517 error = GetLastError();
1518 WLog_Print(context->priv->log, WLOG_ERROR,
1519 "WaitForMultipleObjects failed with error %" PRIu32 "", error);
1520 break;
1521 }
1522
1523 /* Stop Event */
1524 if (status == WAIT_OBJECT_0)
1525 break;
1526
1527 if ((error = rdpgfx_server_handle_messages(context)))
1528 {
1529 WLog_Print(context->priv->log, WLOG_ERROR,
1530 "rdpgfx_server_handle_messages failed with error %" PRIu32 "", error);
1531 break;
1532 }
1533 }
1534
1535 if (error && context->rdpcontext)
1536 setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error");
1537
1538 ExitThread(error);
1539 return error;
1540}
1541
1542static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
1543{
1544 WINPR_ASSERT(context);
1545 RdpgfxServerPrivate* priv = context->priv;
1546 void* buffer = NULL;
1547
1548 WINPR_ASSERT(priv);
1549
1550 if (!priv->isOpened)
1551 {
1552 PULONG pSessionId = NULL;
1553 DWORD BytesReturned = 0;
1554 priv->SessionId = WTS_CURRENT_SESSION;
1555 UINT32 channelId = 0;
1556 BOOL status = TRUE;
1557
1558 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
1559 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
1560 {
1561 WLog_Print(context->priv->log, WLOG_ERROR, "WTSQuerySessionInformationA failed!");
1562 return FALSE;
1563 }
1564
1565 priv->SessionId = (DWORD)*pSessionId;
1566 WTSFreeMemory(pSessionId);
1567 priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME,
1568 WTS_CHANNEL_OPTION_DYNAMIC);
1569
1570 if (!priv->rdpgfx_channel)
1571 {
1572 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelOpenEx failed!");
1573 return FALSE;
1574 }
1575
1576 channelId = WTSChannelGetIdByHandle(priv->rdpgfx_channel);
1577
1578 IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
1579 if (!status)
1580 {
1581 WLog_Print(context->priv->log, WLOG_ERROR, "context->ChannelIdAssigned failed!");
1582 goto fail;
1583 }
1584
1585 /* Query for channel event handle */
1586 if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
1587 &BytesReturned) ||
1588 (BytesReturned != sizeof(HANDLE)))
1589 {
1590 WLog_Print(context->priv->log, WLOG_ERROR,
1591 "WTSVirtualChannelQuery failed "
1592 "or invalid returned size(%" PRIu32 ")",
1593 BytesReturned);
1594
1595 if (buffer)
1596 WTSFreeMemory(buffer);
1597
1598 goto fail;
1599 }
1600
1601 priv->channelEvent = *(HANDLE*)buffer;
1602 WTSFreeMemory(buffer);
1603
1604 if (!(priv->zgfx = zgfx_context_new(TRUE)))
1605 {
1606 WLog_Print(context->priv->log, WLOG_ERROR, "Create zgfx context failed!");
1607 goto fail;
1608 }
1609
1610 priv->isReady = FALSE;
1611 const RDPGFX_CAPSET empty = { 0 };
1612 priv->activeCapSet = empty;
1613 if (priv->ownThread)
1614 {
1615 if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
1616 {
1617 WLog_Print(context->priv->log, WLOG_ERROR, "CreateEvent failed!");
1618 goto fail;
1619 }
1620
1621 if (!(priv->thread =
1622 CreateThread(NULL, 0, rdpgfx_server_thread_func, (void*)context, 0, NULL)))
1623 {
1624 WLog_Print(context->priv->log, WLOG_ERROR, "CreateThread failed!");
1625 goto fail;
1626 }
1627 }
1628
1629 priv->isOpened = TRUE;
1630 return TRUE;
1631 }
1632
1633 WLog_Print(context->priv->log, WLOG_ERROR, "RDPGFX channel is already opened!");
1634 return FALSE;
1635fail:
1636 rdpgfx_server_close(context);
1637 return FALSE;
1638}
1639
1640BOOL rdpgfx_server_close(RdpgfxServerContext* context)
1641{
1642 WINPR_ASSERT(context);
1643
1644 RdpgfxServerPrivate* priv = context->priv;
1645 WINPR_ASSERT(priv);
1646
1647 if (priv->ownThread && priv->thread)
1648 {
1649 (void)SetEvent(priv->stopEvent);
1650
1651 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
1652 {
1653 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
1654 return FALSE;
1655 }
1656
1657 (void)CloseHandle(priv->thread);
1658 (void)CloseHandle(priv->stopEvent);
1659 priv->thread = NULL;
1660 priv->stopEvent = NULL;
1661 }
1662
1663 zgfx_context_free(priv->zgfx);
1664 priv->zgfx = NULL;
1665
1666 if (priv->rdpgfx_channel)
1667 {
1668 (void)WTSVirtualChannelClose(priv->rdpgfx_channel);
1669 priv->rdpgfx_channel = NULL;
1670 }
1671
1672 priv->channelEvent = NULL;
1673 priv->isOpened = FALSE;
1674 priv->isReady = FALSE;
1675 const RDPGFX_CAPSET empty = { 0 };
1676 priv->activeCapSet = empty;
1677 return TRUE;
1678}
1679
1680static BOOL rdpgfx_server_initialize(RdpgfxServerContext* context, BOOL externalThread)
1681{
1682 WINPR_ASSERT(context);
1683 WINPR_ASSERT(context->priv);
1684
1685 if (context->priv->isOpened)
1686 {
1687 WLog_Print(context->priv->log, WLOG_WARN,
1688 "Application error: RDPEGFX channel already initialized, "
1689 "calling in this state is not possible!");
1690 return FALSE;
1691 }
1692
1693 context->priv->ownThread = !externalThread;
1694 return TRUE;
1695}
1696
1697RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm)
1698{
1699 RdpgfxServerContext* context = (RdpgfxServerContext*)calloc(1, sizeof(RdpgfxServerContext));
1700
1701 if (!context)
1702 {
1703 WLog_ERR(TAG, "calloc failed!");
1704 return NULL;
1705 }
1706
1707 context->vcm = vcm;
1708 context->Initialize = rdpgfx_server_initialize;
1709 context->Open = rdpgfx_server_open;
1710 context->Close = rdpgfx_server_close;
1711 context->ResetGraphics = rdpgfx_send_reset_graphics_pdu;
1712 context->StartFrame = rdpgfx_send_start_frame_pdu;
1713 context->EndFrame = rdpgfx_send_end_frame_pdu;
1714 context->SurfaceCommand = rdpgfx_send_surface_command;
1715 context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command;
1716 context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu;
1717 context->CreateSurface = rdpgfx_send_create_surface_pdu;
1718 context->DeleteSurface = rdpgfx_send_delete_surface_pdu;
1719 context->SolidFill = rdpgfx_send_solid_fill_pdu;
1720 context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu;
1721 context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu;
1722 context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu;
1723 context->CacheImportOffer = rdpgfx_process_cache_import_offer_pdu;
1724 context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu;
1725 context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu;
1726 context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu;
1727 context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu;
1728 context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu;
1729 context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu;
1730 context->CapsAdvertise = NULL;
1731 context->CapsConfirm = rdpgfx_send_caps_confirm_pdu;
1732 context->FrameAcknowledge = NULL;
1733 context->QoeFrameAcknowledge = NULL;
1734 RdpgfxServerPrivate* priv = context->priv =
1735 (RdpgfxServerPrivate*)calloc(1, sizeof(RdpgfxServerPrivate));
1736
1737 if (!priv)
1738 {
1739 WLog_ERR(TAG, "calloc failed!");
1740 goto fail;
1741 }
1742
1743 priv->log = WLog_Get(TAG);
1744 if (!priv->log)
1745 goto fail;
1746
1747 /* Create shared input stream */
1748 priv->input_stream = Stream_New(NULL, 4);
1749
1750 if (!priv->input_stream)
1751 {
1752 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!");
1753 goto fail;
1754 }
1755
1756 priv->isOpened = FALSE;
1757 priv->isReady = FALSE;
1758 priv->ownThread = TRUE;
1759
1760 const RDPGFX_CAPSET empty = { 0 };
1761 priv->activeCapSet = empty;
1762 return context;
1763fail:
1764 WINPR_PRAGMA_DIAG_PUSH
1765 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1766 rdpgfx_server_context_free(context);
1767 WINPR_PRAGMA_DIAG_POP
1768 return NULL;
1769}
1770
1771void rdpgfx_server_context_free(RdpgfxServerContext* context)
1772{
1773 if (!context)
1774 return;
1775
1776 rdpgfx_server_close(context);
1777
1778 if (context->priv)
1779 Stream_Free(context->priv->input_stream, TRUE);
1780
1781 free(context->priv);
1782 free(context);
1783}
1784
1785HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context)
1786{
1787 if (!context)
1788 return NULL;
1789 if (!context->priv)
1790 return NULL;
1791 return context->priv->channelEvent;
1792}
1793
1794/*
1795 * Handle rpdgfx messages - server side
1796 *
1797 * @param Server side context
1798 *
1799 * @return 0 on success
1800 * ERROR_NO_DATA if no data could be read this time
1801 * otherwise a Win32 error code
1802 */
1803UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
1804{
1805 DWORD BytesReturned = 0;
1806 void* buffer = NULL;
1807 UINT ret = CHANNEL_RC_OK;
1808
1809 WINPR_ASSERT(context);
1810 WINPR_ASSERT(context->priv);
1811
1812 RdpgfxServerPrivate* priv = context->priv;
1813 wStream* s = priv->input_stream;
1814
1815 /* Check whether the dynamic channel is ready */
1816 if (!priv->isReady)
1817 {
1818 if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer,
1819 &BytesReturned) == FALSE)
1820 {
1821 if (GetLastError() == ERROR_NO_DATA)
1822 return ERROR_NO_DATA;
1823
1824 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelQuery failed");
1825 return ERROR_INTERNAL_ERROR;
1826 }
1827
1828 priv->isReady = *((BOOL*)buffer);
1829 WTSFreeMemory(buffer);
1830 }
1831
1832 /* Consume channel event only after the gfx dynamic channel is ready */
1833 if (priv->isReady)
1834 {
1835 Stream_SetPosition(s, 0);
1836
1837 if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, NULL, 0, &BytesReturned))
1838 {
1839 if (GetLastError() == ERROR_NO_DATA)
1840 return ERROR_NO_DATA;
1841
1842 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
1843 return ERROR_INTERNAL_ERROR;
1844 }
1845
1846 if (BytesReturned < 1)
1847 return CHANNEL_RC_OK;
1848
1849 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
1850 {
1851 WLog_Print(context->priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!");
1852 return CHANNEL_RC_NO_MEMORY;
1853 }
1854
1855 const size_t len = Stream_Capacity(s);
1856 if (len > UINT32_MAX)
1857 return ERROR_INTERNAL_ERROR;
1858 if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, Stream_BufferAs(s, char), (UINT32)len,
1859 &BytesReturned) == FALSE)
1860 {
1861 WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!");
1862 return ERROR_INTERNAL_ERROR;
1863 }
1864
1865 Stream_SetLength(s, BytesReturned);
1866 Stream_SetPosition(s, 0);
1867
1868 while (Stream_GetPosition(s) < Stream_Length(s))
1869 {
1870 if ((ret = rdpgfx_server_receive_pdu(context, s)))
1871 {
1872 WLog_Print(context->priv->log, WLOG_ERROR,
1873 "rdpgfx_server_receive_pdu "
1874 "failed with error %" PRIu32 "!",
1875 ret);
1876 return ret;
1877 }
1878 }
1879 }
1880
1881 return ret;
1882}