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