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