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