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