1 /**
2 * FreeRDP: A Remote Desktop Protocol Implementation
3 * Graphics Pipeline Extension
4 *
5 * Copyright 2016 Jiang Zihao <zihao.jiang@yahoo.com>
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <assert.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include <winpr/crt.h>
30 #include <winpr/synch.h>
31 #include <winpr/thread.h>
32 #include <winpr/stream.h>
33
34 #include <freerdp/channels/wtsvc.h>
35 #include <freerdp/channels/log.h>
36
37 #include "rdpgfx_common.h"
38 #include "rdpgfx_main.h"
39
40 #define TAG CHANNELS_TAG("rdpgfx.server")
41 #define RDPGFX_RESET_GRAPHICS_PDU_SIZE 340
42
43 /**
44 * Function description
45 * Calculate packet size from data length.
46 * It would be data length + header.
47 *
48 * @param dataLen estimated data length without header
49 *
50 * @return new stream
51 */
rdpgfx_pdu_length(UINT32 dataLen)52 static INLINE UINT32 rdpgfx_pdu_length(UINT32 dataLen)
53 {
54 return RDPGFX_HEADER_SIZE + dataLen;
55 }
56
rdpgfx_server_packet_init_header(wStream * s,UINT16 cmdId,UINT32 pduLength)57 static INLINE UINT rdpgfx_server_packet_init_header(wStream* s, UINT16 cmdId, UINT32 pduLength)
58 {
59 RDPGFX_HEADER header;
60 header.flags = 0;
61 header.cmdId = cmdId;
62 header.pduLength = pduLength;
63 /* Write header. Note that actual length might be changed
64 * after the entire packet has been constructed. */
65 return rdpgfx_write_header(s, &header);
66 }
67
68 /**
69 * Function description
70 * Complete the rdpgfx packet header.
71 *
72 * @param s stream
73 * @param start saved start pos of the packet in the stream
74 */
rdpgfx_server_packet_complete_header(wStream * s,size_t start)75 static INLINE BOOL rdpgfx_server_packet_complete_header(wStream* s, size_t start)
76 {
77 const size_t current = Stream_GetPosition(s);
78 const size_t cap = Stream_Capacity(s);
79 if (cap < start + RDPGFX_HEADER_SIZE)
80 return FALSE;
81 /* Fill actual length */
82 Stream_SetPosition(s, start + RDPGFX_HEADER_SIZE - sizeof(UINT32));
83 Stream_Write_UINT32(s, current - start); /* pduLength (4 bytes) */
84 Stream_SetPosition(s, current);
85 return TRUE;
86 }
87
88 /**
89 * Function description
90 * Send the stream for rdpgfx server packet.
91 * The packet would be compressed according to [MS-RDPEGFX].
92 *
93 * @return 0 on success, otherwise a Win32 error code
94 */
rdpgfx_server_packet_send(RdpgfxServerContext * context,wStream * s)95 static UINT rdpgfx_server_packet_send(RdpgfxServerContext* context, wStream* s)
96 {
97 UINT error;
98 UINT32 flags = 0;
99 ULONG written;
100 BYTE* pSrcData = Stream_Buffer(s);
101 UINT32 SrcSize = Stream_GetPosition(s);
102 wStream* fs;
103 /* Allocate new stream with enough capacity. Additional overhead is
104 * descriptor (1 bytes) + segmentCount (2 bytes) + uncompressedSize (4 bytes)
105 * + segmentCount * size (4 bytes) */
106 fs = Stream_New(NULL, SrcSize + 7 + (SrcSize / ZGFX_SEGMENTED_MAXSIZE + 1) * 4);
107
108 if (!fs)
109 {
110 WLog_ERR(TAG, "Stream_New failed!");
111 error = CHANNEL_RC_NO_MEMORY;
112 goto out;
113 }
114
115 if (zgfx_compress_to_stream(context->priv->zgfx, fs, pSrcData, SrcSize, &flags) < 0)
116 {
117 WLog_ERR(TAG, "zgfx_compress_to_stream failed!");
118 error = ERROR_INTERNAL_ERROR;
119 goto out;
120 }
121
122 if (!WTSVirtualChannelWrite(context->priv->rdpgfx_channel, (PCHAR)Stream_Buffer(fs),
123 Stream_GetPosition(fs), &written))
124 {
125 WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
126 error = ERROR_INTERNAL_ERROR;
127 goto out;
128 }
129
130 if (written < Stream_GetPosition(fs))
131 {
132 WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
133 Stream_GetPosition(fs));
134 }
135
136 error = CHANNEL_RC_OK;
137 out:
138 Stream_Free(fs, TRUE);
139 Stream_Free(s, TRUE);
140 return error;
141 }
142
143 /**
144 * Function description
145 * Create new stream for single rdpgfx packet. The new stream length
146 * would be required data length + header. The header will be written
147 * to the stream before return, but the pduLength field might be
148 * changed in rdpgfx_server_single_packet_send.
149 *
150 * @param cmdId
151 * @param dataLen estimated data length without header
152 *
153 * @return new stream
154 */
rdpgfx_server_single_packet_new(UINT16 cmdId,UINT32 dataLen)155 static wStream* rdpgfx_server_single_packet_new(UINT16 cmdId, UINT32 dataLen)
156 {
157 UINT error;
158 wStream* s;
159 UINT32 pduLength = rdpgfx_pdu_length(dataLen);
160 s = Stream_New(NULL, pduLength);
161
162 if (!s)
163 {
164 WLog_ERR(TAG, "Stream_New failed!");
165 goto error;
166 }
167
168 if ((error = rdpgfx_server_packet_init_header(s, cmdId, pduLength)))
169 {
170 WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error);
171 goto error;
172 }
173
174 return s;
175 error:
176 Stream_Free(s, TRUE);
177 return NULL;
178 }
179
180 /**
181 * Function description
182 * Send the stream for single rdpgfx packet.
183 * The header will be filled with actual length.
184 * The packet would be compressed according to [MS-RDPEGFX].
185 *
186 * @return 0 on success, otherwise a Win32 error code
187 */
rdpgfx_server_single_packet_send(RdpgfxServerContext * context,wStream * s)188 static INLINE UINT rdpgfx_server_single_packet_send(RdpgfxServerContext* context, wStream* s)
189 {
190 /* Fill actual length */
191 rdpgfx_server_packet_complete_header(s, 0);
192 return rdpgfx_server_packet_send(context, s);
193 }
194
195 /**
196 * Function description
197 *
198 * @return 0 on success, otherwise a Win32 error code
199 */
rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext * context,const RDPGFX_CAPS_CONFIRM_PDU * capsConfirm)200 static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context,
201 const RDPGFX_CAPS_CONFIRM_PDU* capsConfirm)
202 {
203 RDPGFX_CAPSET* capsSet = capsConfirm->capsSet;
204 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CAPSCONFIRM,
205 RDPGFX_CAPSET_BASE_SIZE + capsSet->length);
206
207 if (!s)
208 {
209 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
210 return CHANNEL_RC_NO_MEMORY;
211 }
212
213 Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */
214 Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
215
216 if (capsSet->length >= 4)
217 {
218 Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
219 Stream_Zero(s, capsSet->length - 4);
220 }
221 else
222 Stream_Zero(s, capsSet->length);
223
224 return rdpgfx_server_single_packet_send(context, s);
225 }
226
227 /**
228 * Function description
229 *
230 * @return 0 on success, otherwise a Win32 error code
231 */
rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext * context,const RDPGFX_RESET_GRAPHICS_PDU * pdu)232 static UINT rdpgfx_send_reset_graphics_pdu(RdpgfxServerContext* context,
233 const RDPGFX_RESET_GRAPHICS_PDU* pdu)
234 {
235 UINT32 index;
236 MONITOR_DEF* monitor;
237 wStream* s;
238
239 /* Check monitorCount. This ensures total size within 340 bytes) */
240 if (pdu->monitorCount >= 16)
241 {
242 WLog_ERR(TAG, "Monitor count MUST be less than or equal to 16: %" PRIu32 "",
243 pdu->monitorCount);
244 return ERROR_INVALID_DATA;
245 }
246
247 s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_RESETGRAPHICS,
248 RDPGFX_RESET_GRAPHICS_PDU_SIZE - RDPGFX_HEADER_SIZE);
249
250 if (!s)
251 {
252 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
253 return CHANNEL_RC_NO_MEMORY;
254 }
255
256 Stream_Write_UINT32(s, pdu->width); /* width (4 bytes) */
257 Stream_Write_UINT32(s, pdu->height); /* height (4 bytes) */
258 Stream_Write_UINT32(s, pdu->monitorCount); /* monitorCount (4 bytes) */
259
260 for (index = 0; index < pdu->monitorCount; index++)
261 {
262 monitor = &(pdu->monitorDefArray[index]);
263 Stream_Write_UINT32(s, monitor->left); /* left (4 bytes) */
264 Stream_Write_UINT32(s, monitor->top); /* top (4 bytes) */
265 Stream_Write_UINT32(s, monitor->right); /* right (4 bytes) */
266 Stream_Write_UINT32(s, monitor->bottom); /* bottom (4 bytes) */
267 Stream_Write_UINT32(s, monitor->flags); /* flags (4 bytes) */
268 }
269
270 /* pad (total size must be 340 bytes) */
271 Stream_SetPosition(s, RDPGFX_RESET_GRAPHICS_PDU_SIZE);
272 return rdpgfx_server_single_packet_send(context, s);
273 }
274
275 /**
276 * Function description
277 *
278 * @return 0 on success, otherwise a Win32 error code
279 */
rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext * context,const RDPGFX_EVICT_CACHE_ENTRY_PDU * pdu)280 static UINT rdpgfx_send_evict_cache_entry_pdu(RdpgfxServerContext* context,
281 const RDPGFX_EVICT_CACHE_ENTRY_PDU* pdu)
282 {
283 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_EVICTCACHEENTRY, 2);
284
285 if (!s)
286 {
287 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
288 return CHANNEL_RC_NO_MEMORY;
289 }
290
291 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
292 return rdpgfx_server_single_packet_send(context, s);
293 }
294
295 /**
296 * Function description
297 *
298 * @return 0 on success, otherwise a Win32 error code
299 */
rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext * context,const RDPGFX_CACHE_IMPORT_REPLY_PDU * pdu)300 static UINT rdpgfx_send_cache_import_reply_pdu(RdpgfxServerContext* context,
301 const RDPGFX_CACHE_IMPORT_REPLY_PDU* pdu)
302 {
303 UINT16 index;
304 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CACHEIMPORTREPLY,
305 2 + 2 * pdu->importedEntriesCount);
306
307 if (!s)
308 {
309 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
310 return CHANNEL_RC_NO_MEMORY;
311 }
312
313 /* importedEntriesCount (2 bytes) */
314 Stream_Write_UINT16(s, pdu->importedEntriesCount);
315
316 for (index = 0; index < pdu->importedEntriesCount; index++)
317 {
318 Stream_Write_UINT16(s, pdu->cacheSlots[index]); /* cacheSlot (2 bytes) */
319 }
320
321 return rdpgfx_server_single_packet_send(context, s);
322 }
323
324 /**
325 * Function description
326 *
327 * @return 0 on success, otherwise a Win32 error code
328 */
rdpgfx_send_create_surface_pdu(RdpgfxServerContext * context,const RDPGFX_CREATE_SURFACE_PDU * pdu)329 static UINT rdpgfx_send_create_surface_pdu(RdpgfxServerContext* context,
330 const RDPGFX_CREATE_SURFACE_PDU* pdu)
331 {
332 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_CREATESURFACE, 7);
333
334 if (!s)
335 {
336 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
337 return CHANNEL_RC_NO_MEMORY;
338 }
339
340 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
341 Stream_Write_UINT16(s, pdu->width); /* width (2 bytes) */
342 Stream_Write_UINT16(s, pdu->height); /* height (2 bytes) */
343 Stream_Write_UINT8(s, pdu->pixelFormat); /* RDPGFX_PIXELFORMAT (1 byte) */
344 return rdpgfx_server_single_packet_send(context, s);
345 }
346
347 /**
348 * Function description
349 *
350 * @return 0 on success, otherwise a Win32 error code
351 */
rdpgfx_send_delete_surface_pdu(RdpgfxServerContext * context,const RDPGFX_DELETE_SURFACE_PDU * pdu)352 static UINT rdpgfx_send_delete_surface_pdu(RdpgfxServerContext* context,
353 const RDPGFX_DELETE_SURFACE_PDU* pdu)
354 {
355 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_DELETESURFACE, 2);
356
357 if (!s)
358 {
359 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
360 return CHANNEL_RC_NO_MEMORY;
361 }
362
363 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
364 return rdpgfx_server_single_packet_send(context, s);
365 }
366
rdpgfx_write_start_frame_pdu(wStream * s,const RDPGFX_START_FRAME_PDU * pdu)367 static INLINE BOOL rdpgfx_write_start_frame_pdu(wStream* s, const RDPGFX_START_FRAME_PDU* pdu)
368 {
369 if (!Stream_EnsureRemainingCapacity(s, 8))
370 return FALSE;
371 Stream_Write_UINT32(s, pdu->timestamp); /* timestamp (4 bytes) */
372 Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
373 return TRUE;
374 }
375
rdpgfx_write_end_frame_pdu(wStream * s,const RDPGFX_END_FRAME_PDU * pdu)376 static INLINE BOOL rdpgfx_write_end_frame_pdu(wStream* s, const RDPGFX_END_FRAME_PDU* pdu)
377 {
378 if (!Stream_EnsureRemainingCapacity(s, 4))
379 return FALSE;
380 Stream_Write_UINT32(s, pdu->frameId); /* frameId (4 bytes) */
381 return TRUE;
382 }
383
384 /**
385 * Function description
386 *
387 * @return 0 on success, otherwise a Win32 error code
388 */
rdpgfx_send_start_frame_pdu(RdpgfxServerContext * context,const RDPGFX_START_FRAME_PDU * pdu)389 static UINT rdpgfx_send_start_frame_pdu(RdpgfxServerContext* context,
390 const RDPGFX_START_FRAME_PDU* pdu)
391 {
392 wStream* s =
393 rdpgfx_server_single_packet_new(RDPGFX_CMDID_STARTFRAME, RDPGFX_START_FRAME_PDU_SIZE);
394
395 if (!s)
396 {
397 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
398 return CHANNEL_RC_NO_MEMORY;
399 }
400
401 rdpgfx_write_start_frame_pdu(s, pdu);
402 return rdpgfx_server_single_packet_send(context, s);
403 }
404
405 /**
406 * Function description
407 *
408 * @return 0 on success, otherwise a Win32 error code
409 */
rdpgfx_send_end_frame_pdu(RdpgfxServerContext * context,const RDPGFX_END_FRAME_PDU * pdu)410 static UINT rdpgfx_send_end_frame_pdu(RdpgfxServerContext* context, const RDPGFX_END_FRAME_PDU* pdu)
411 {
412 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_ENDFRAME, RDPGFX_END_FRAME_PDU_SIZE);
413
414 if (!s)
415 {
416 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
417 return CHANNEL_RC_NO_MEMORY;
418 }
419
420 rdpgfx_write_end_frame_pdu(s, pdu);
421 return rdpgfx_server_single_packet_send(context, s);
422 }
423
424 /**
425 * Function description
426 * Estimate RFX_AVC420_BITMAP_STREAM structure size in stream
427 *
428 * @return estimated size
429 */
rdpgfx_estimate_h264_avc420(const RDPGFX_AVC420_BITMAP_STREAM * havc420)430 static INLINE UINT32 rdpgfx_estimate_h264_avc420(const RDPGFX_AVC420_BITMAP_STREAM* havc420)
431 {
432 /* H264 metadata + H264 stream. See rdpgfx_write_h264_avc420 */
433 return sizeof(UINT32) /* numRegionRects */
434 + 10 /* regionRects + quantQualityVals */
435 * havc420->meta.numRegionRects +
436 havc420->length;
437 }
438
439 /**
440 * Function description
441 * Estimate surface command packet size in stream without header
442 *
443 * @return estimated size
444 */
rdpgfx_estimate_surface_command(const RDPGFX_SURFACE_COMMAND * cmd)445 static INLINE UINT32 rdpgfx_estimate_surface_command(const RDPGFX_SURFACE_COMMAND* cmd)
446 {
447 RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL;
448 RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL;
449 UINT32 h264Size = 0;
450
451 /* Estimate stream size according to codec. */
452 switch (cmd->codecId)
453 {
454 case RDPGFX_CODECID_CAPROGRESSIVE:
455 case RDPGFX_CODECID_CAPROGRESSIVE_V2:
456 return RDPGFX_WIRE_TO_SURFACE_PDU_2_SIZE + cmd->length;
457
458 case RDPGFX_CODECID_AVC420:
459 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
460 h264Size = rdpgfx_estimate_h264_avc420(havc420);
461 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
462
463 case RDPGFX_CODECID_AVC444:
464 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
465 h264Size = sizeof(UINT32); /* cbAvc420EncodedBitstream1 */
466 /* avc420EncodedBitstream1 */
467 havc420 = &(havc444->bitstream[0]);
468 h264Size += rdpgfx_estimate_h264_avc420(havc420);
469
470 /* avc420EncodedBitstream2 */
471 if (havc444->LC == 0)
472 {
473 havc420 = &(havc444->bitstream[1]);
474 h264Size += rdpgfx_estimate_h264_avc420(havc420);
475 }
476
477 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + h264Size;
478
479 default:
480 return RDPGFX_WIRE_TO_SURFACE_PDU_1_SIZE + cmd->length;
481 }
482 }
483
484 /**
485 * Function description
486 * Resolve RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2
487 * according to codecId
488 *
489 * @return 0 on success, otherwise a Win32 error code
490 */
rdpgfx_surface_command_cmdid(const RDPGFX_SURFACE_COMMAND * cmd)491 static INLINE UINT16 rdpgfx_surface_command_cmdid(const RDPGFX_SURFACE_COMMAND* cmd)
492 {
493 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
494 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
495 {
496 return RDPGFX_CMDID_WIRETOSURFACE_2;
497 }
498
499 return RDPGFX_CMDID_WIRETOSURFACE_1;
500 }
501
502 /**
503 * Function description
504 *
505 * @return 0 on success, otherwise a Win32 error code
506 */
rdpgfx_write_h264_metablock(wStream * s,const RDPGFX_H264_METABLOCK * meta)507 static UINT rdpgfx_write_h264_metablock(wStream* s, const RDPGFX_H264_METABLOCK* meta)
508 {
509 UINT32 index;
510 RECTANGLE_16* regionRect;
511 RDPGFX_H264_QUANT_QUALITY* quantQualityVal;
512 UINT error = CHANNEL_RC_OK;
513
514 if (!Stream_EnsureRemainingCapacity(s, 4 + meta->numRegionRects * 10))
515 return ERROR_OUTOFMEMORY;
516
517 Stream_Write_UINT32(s, meta->numRegionRects); /* numRegionRects (4 bytes) */
518
519 for (index = 0; index < meta->numRegionRects; index++)
520 {
521 regionRect = &(meta->regionRects[index]);
522
523 if ((error = rdpgfx_write_rect16(s, regionRect)))
524 {
525 WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
526 return error;
527 }
528 }
529
530 for (index = 0; index < meta->numRegionRects; index++)
531 {
532 quantQualityVal = &(meta->quantQualityVals[index]);
533 Stream_Write_UINT8(s, quantQualityVal->qp | (quantQualityVal->r << 6) |
534 (quantQualityVal->p << 7)); /* qpVal (1 byte) */
535 /* qualityVal (1 byte) */
536 Stream_Write_UINT8(s, quantQualityVal->qualityVal);
537 }
538
539 return error;
540 }
541
542 /**
543 * Function description
544 * Write RFX_AVC420_BITMAP_STREAM structure to stream
545 *
546 * @return 0 on success, otherwise a Win32 error code
547 */
rdpgfx_write_h264_avc420(wStream * s,RDPGFX_AVC420_BITMAP_STREAM * havc420)548 static INLINE UINT rdpgfx_write_h264_avc420(wStream* s, RDPGFX_AVC420_BITMAP_STREAM* havc420)
549 {
550 UINT error = CHANNEL_RC_OK;
551
552 if ((error = rdpgfx_write_h264_metablock(s, &(havc420->meta))))
553 {
554 WLog_ERR(TAG, "rdpgfx_write_h264_metablock failed with error %" PRIu32 "!", error);
555 return error;
556 }
557
558 if (!Stream_EnsureRemainingCapacity(s, havc420->length))
559 return ERROR_OUTOFMEMORY;
560
561 Stream_Write(s, havc420->data, havc420->length);
562 return error;
563 }
564
565 /**
566 * Function description
567 * Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2
568 * to the stream according to RDPGFX_SURFACE_COMMAND message
569 *
570 * @return 0 on success, otherwise a Win32 error code
571 */
rdpgfx_write_surface_command(wStream * s,const RDPGFX_SURFACE_COMMAND * cmd)572 static UINT rdpgfx_write_surface_command(wStream* s, const RDPGFX_SURFACE_COMMAND* cmd)
573 {
574 UINT error = CHANNEL_RC_OK;
575 RDPGFX_AVC420_BITMAP_STREAM* havc420 = NULL;
576 RDPGFX_AVC444_BITMAP_STREAM* havc444 = NULL;
577 UINT32 bitmapDataStart = 0;
578 UINT32 bitmapDataLength = 0;
579 UINT8 pixelFormat = 0;
580
581 switch (cmd->format)
582 {
583 case PIXEL_FORMAT_BGRX32:
584 pixelFormat = GFX_PIXEL_FORMAT_XRGB_8888;
585 break;
586
587 case PIXEL_FORMAT_BGRA32:
588 pixelFormat = GFX_PIXEL_FORMAT_ARGB_8888;
589 break;
590
591 default:
592 WLog_ERR(TAG, "Format %s not supported!", FreeRDPGetColorFormatName(cmd->format));
593 return ERROR_INVALID_DATA;
594 }
595
596 if (cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE ||
597 cmd->codecId == RDPGFX_CODECID_CAPROGRESSIVE_V2)
598 {
599 if (!Stream_EnsureRemainingCapacity(s, 13 + cmd->length))
600 return ERROR_INTERNAL_ERROR;
601 /* Write RDPGFX_CMDID_WIRETOSURFACE_2 format for CAPROGRESSIVE */
602 Stream_Write_UINT16(s, cmd->surfaceId); /* surfaceId (2 bytes) */
603 Stream_Write_UINT16(s, cmd->codecId); /* codecId (2 bytes) */
604 Stream_Write_UINT32(s, cmd->contextId); /* codecContextId (4 bytes) */
605 Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */
606 Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */
607 Stream_Write(s, cmd->data, cmd->length);
608 }
609 else
610 {
611 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 format for others */
612 if (!Stream_EnsureRemainingCapacity(s, 17))
613 return ERROR_INTERNAL_ERROR;
614 Stream_Write_UINT16(s, cmd->surfaceId); /* surfaceId (2 bytes) */
615 Stream_Write_UINT16(s, cmd->codecId); /* codecId (2 bytes) */
616 Stream_Write_UINT8(s, pixelFormat); /* pixelFormat (1 byte) */
617 Stream_Write_UINT16(s, cmd->left); /* left (2 bytes) */
618 Stream_Write_UINT16(s, cmd->top); /* top (2 bytes) */
619 Stream_Write_UINT16(s, cmd->right); /* right (2 bytes) */
620 Stream_Write_UINT16(s, cmd->bottom); /* bottom (2 bytes) */
621 Stream_Write_UINT32(s, cmd->length); /* bitmapDataLength (4 bytes) */
622 bitmapDataStart = Stream_GetPosition(s);
623
624 if (cmd->codecId == RDPGFX_CODECID_AVC420)
625 {
626 havc420 = (RDPGFX_AVC420_BITMAP_STREAM*)cmd->extra;
627 error = rdpgfx_write_h264_avc420(s, havc420);
628
629 if (error != CHANNEL_RC_OK)
630 {
631 WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!");
632 return error;
633 }
634 }
635 else if ((cmd->codecId == RDPGFX_CODECID_AVC444) ||
636 (cmd->codecId == RDPGFX_CODECID_AVC444v2))
637 {
638 havc444 = (RDPGFX_AVC444_BITMAP_STREAM*)cmd->extra;
639 havc420 = &(havc444->bitstream[0]); /* avc420EncodedBitstreamInfo (4 bytes) */
640 if (!Stream_EnsureRemainingCapacity(s, 4))
641 return ERROR_INTERNAL_ERROR;
642 Stream_Write_UINT32(s, havc444->cbAvc420EncodedBitstream1 | (havc444->LC << 30UL));
643 /* avc420EncodedBitstream1 */
644 error = rdpgfx_write_h264_avc420(s, havc420);
645
646 if (error != CHANNEL_RC_OK)
647 {
648 WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!");
649 return error;
650 }
651
652 /* avc420EncodedBitstream2 */
653 if (havc444->LC == 0)
654 {
655 havc420 = &(havc444->bitstream[1]);
656 error = rdpgfx_write_h264_avc420(s, havc420);
657
658 if (error != CHANNEL_RC_OK)
659 {
660 WLog_ERR(TAG, "rdpgfx_write_h264_avc420 failed!");
661 return error;
662 }
663 }
664 }
665 else
666 {
667 if (!Stream_EnsureRemainingCapacity(s, cmd->length))
668 return ERROR_INTERNAL_ERROR;
669 Stream_Write(s, cmd->data, cmd->length);
670 }
671
672 /* Fill actual bitmap data length */
673 bitmapDataLength = Stream_GetPosition(s) - bitmapDataStart;
674 Stream_SetPosition(s, bitmapDataStart - sizeof(UINT32));
675 if (!Stream_EnsureRemainingCapacity(s, 4))
676 return ERROR_INTERNAL_ERROR;
677 Stream_Write_UINT32(s, bitmapDataLength); /* bitmapDataLength (4 bytes) */
678 if (!Stream_SafeSeek(s, bitmapDataLength))
679 return ERROR_INTERNAL_ERROR;
680 }
681
682 return error;
683 }
684
685 /**
686 * Function description
687 * Send RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2
688 * message according to codecId
689 *
690 * @return 0 on success, otherwise a Win32 error code
691 */
rdpgfx_send_surface_command(RdpgfxServerContext * context,const RDPGFX_SURFACE_COMMAND * cmd)692 static UINT rdpgfx_send_surface_command(RdpgfxServerContext* context,
693 const RDPGFX_SURFACE_COMMAND* cmd)
694 {
695 UINT error = CHANNEL_RC_OK;
696 wStream* s;
697 s = rdpgfx_server_single_packet_new(rdpgfx_surface_command_cmdid(cmd),
698 rdpgfx_estimate_surface_command(cmd));
699
700 if (!s)
701 {
702 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
703 return CHANNEL_RC_NO_MEMORY;
704 }
705
706 error = rdpgfx_write_surface_command(s, cmd);
707
708 if (error != CHANNEL_RC_OK)
709 {
710 WLog_ERR(TAG, "rdpgfx_write_surface_command failed!");
711 goto error;
712 }
713
714 return rdpgfx_server_single_packet_send(context, s);
715 error:
716 Stream_Free(s, TRUE);
717 return error;
718 }
719
720 /**
721 * Function description
722 * Send RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2
723 * message according to codecId.
724 * Prepend/append start/end frame message in same packet if exists.
725 *
726 * @return 0 on success, otherwise a Win32 error code
727 */
rdpgfx_send_surface_frame_command(RdpgfxServerContext * context,const RDPGFX_SURFACE_COMMAND * cmd,const RDPGFX_START_FRAME_PDU * startFrame,const RDPGFX_END_FRAME_PDU * endFrame)728 static UINT rdpgfx_send_surface_frame_command(RdpgfxServerContext* context,
729 const RDPGFX_SURFACE_COMMAND* cmd,
730 const RDPGFX_START_FRAME_PDU* startFrame,
731 const RDPGFX_END_FRAME_PDU* endFrame)
732
733 {
734 UINT error = CHANNEL_RC_OK;
735 wStream* s;
736 UINT32 position = 0;
737 UINT32 size = rdpgfx_pdu_length(rdpgfx_estimate_surface_command(cmd));
738
739 if (startFrame)
740 {
741 size += rdpgfx_pdu_length(RDPGFX_START_FRAME_PDU_SIZE);
742 }
743
744 if (endFrame)
745 {
746 size += rdpgfx_pdu_length(RDPGFX_END_FRAME_PDU_SIZE);
747 }
748
749 s = Stream_New(NULL, size);
750
751 if (!s)
752 {
753 WLog_ERR(TAG, "Stream_New failed!");
754 return CHANNEL_RC_NO_MEMORY;
755 }
756
757 /* Write start frame if exists */
758 if (startFrame)
759 {
760 position = Stream_GetPosition(s);
761 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_STARTFRAME, 0);
762
763 if (error != CHANNEL_RC_OK)
764 {
765 WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error);
766 goto error;
767 }
768
769 if (!rdpgfx_write_start_frame_pdu(s, startFrame) ||
770 !rdpgfx_server_packet_complete_header(s, position))
771 goto error;
772 }
773
774 /* Write RDPGFX_CMDID_WIRETOSURFACE_1 or RDPGFX_CMDID_WIRETOSURFACE_2 */
775 position = Stream_GetPosition(s);
776 error = rdpgfx_server_packet_init_header(s, rdpgfx_surface_command_cmdid(cmd),
777 0); // Actual length will be filled later
778
779 if (error != CHANNEL_RC_OK)
780 {
781 WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error);
782 goto error;
783 }
784
785 error = rdpgfx_write_surface_command(s, cmd);
786
787 if (error != CHANNEL_RC_OK)
788 {
789 WLog_ERR(TAG, "rdpgfx_write_surface_command failed!");
790 goto error;
791 }
792
793 if (!rdpgfx_server_packet_complete_header(s, position))
794 goto error;
795
796 /* Write end frame if exists */
797 if (endFrame)
798 {
799 position = Stream_GetPosition(s);
800 error = rdpgfx_server_packet_init_header(s, RDPGFX_CMDID_ENDFRAME, 0);
801
802 if (error != CHANNEL_RC_OK)
803 {
804 WLog_ERR(TAG, "Failed to init header with error %" PRIu32 "!", error);
805 goto error;
806 }
807
808 if (!rdpgfx_write_end_frame_pdu(s, endFrame) ||
809 !rdpgfx_server_packet_complete_header(s, position))
810 goto error;
811 }
812
813 return rdpgfx_server_packet_send(context, s);
814 error:
815 Stream_Free(s, TRUE);
816 return error;
817 }
818
819 /**
820 * Function description
821 *
822 * @return 0 on success, otherwise a Win32 error code
823 */
rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext * context,const RDPGFX_DELETE_ENCODING_CONTEXT_PDU * pdu)824 static UINT rdpgfx_send_delete_encoding_context_pdu(RdpgfxServerContext* context,
825 const RDPGFX_DELETE_ENCODING_CONTEXT_PDU* pdu)
826 {
827 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_DELETEENCODINGCONTEXT, 6);
828
829 if (!s)
830 {
831 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
832 return CHANNEL_RC_NO_MEMORY;
833 }
834
835 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
836 Stream_Write_UINT32(s, pdu->codecContextId); /* codecContextId (4 bytes) */
837 return rdpgfx_server_single_packet_send(context, s);
838 }
839
840 /**
841 * Function description
842 *
843 * @return 0 on success, otherwise a Win32 error code
844 */
rdpgfx_send_solid_fill_pdu(RdpgfxServerContext * context,const RDPGFX_SOLID_FILL_PDU * pdu)845 static UINT rdpgfx_send_solid_fill_pdu(RdpgfxServerContext* context,
846 const RDPGFX_SOLID_FILL_PDU* pdu)
847 {
848 UINT error = CHANNEL_RC_OK;
849 UINT16 index;
850 RECTANGLE_16* fillRect;
851 wStream* s =
852 rdpgfx_server_single_packet_new(RDPGFX_CMDID_SOLIDFILL, 8 + 8 * pdu->fillRectCount);
853
854 if (!s)
855 {
856 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
857 return CHANNEL_RC_NO_MEMORY;
858 }
859
860 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
861
862 /* fillPixel (4 bytes) */
863 if ((error = rdpgfx_write_color32(s, &(pdu->fillPixel))))
864 {
865 WLog_ERR(TAG, "rdpgfx_write_color32 failed with error %" PRIu32 "!", error);
866 goto error;
867 }
868
869 Stream_Write_UINT16(s, pdu->fillRectCount); /* fillRectCount (2 bytes) */
870
871 for (index = 0; index < pdu->fillRectCount; index++)
872 {
873 fillRect = &(pdu->fillRects[index]);
874
875 if ((error = rdpgfx_write_rect16(s, fillRect)))
876 {
877 WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
878 goto error;
879 }
880 }
881
882 return rdpgfx_server_single_packet_send(context, s);
883 error:
884 Stream_Free(s, TRUE);
885 return error;
886 }
887
888 /**
889 * Function description
890 *
891 * @return 0 on success, otherwise a Win32 error code
892 */
rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext * context,const RDPGFX_SURFACE_TO_SURFACE_PDU * pdu)893 static UINT rdpgfx_send_surface_to_surface_pdu(RdpgfxServerContext* context,
894 const RDPGFX_SURFACE_TO_SURFACE_PDU* pdu)
895 {
896 UINT error = CHANNEL_RC_OK;
897 UINT16 index;
898 RDPGFX_POINT16* destPt;
899 wStream* s =
900 rdpgfx_server_single_packet_new(RDPGFX_CMDID_SURFACETOSURFACE, 14 + 4 * pdu->destPtsCount);
901
902 if (!s)
903 {
904 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
905 return CHANNEL_RC_NO_MEMORY;
906 }
907
908 Stream_Write_UINT16(s, pdu->surfaceIdSrc); /* surfaceIdSrc (2 bytes) */
909 Stream_Write_UINT16(s, pdu->surfaceIdDest); /* surfaceIdDest (2 bytes) */
910
911 /* rectSrc (8 bytes ) */
912 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
913 {
914 WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
915 goto error;
916 }
917
918 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
919
920 for (index = 0; index < pdu->destPtsCount; index++)
921 {
922 destPt = &(pdu->destPts[index]);
923
924 if ((error = rdpgfx_write_point16(s, destPt)))
925 {
926 WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %" PRIu32 "!", error);
927 goto error;
928 }
929 }
930
931 return rdpgfx_server_single_packet_send(context, s);
932 error:
933 Stream_Free(s, TRUE);
934 return error;
935 }
936
937 /**
938 * Function description
939 *
940 * @return 0 on success, otherwise a Win32 error code
941 */
rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext * context,const RDPGFX_SURFACE_TO_CACHE_PDU * pdu)942 static UINT rdpgfx_send_surface_to_cache_pdu(RdpgfxServerContext* context,
943 const RDPGFX_SURFACE_TO_CACHE_PDU* pdu)
944 {
945 UINT error = CHANNEL_RC_OK;
946 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_SURFACETOCACHE, 20);
947
948 if (!s)
949 {
950 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
951 return CHANNEL_RC_NO_MEMORY;
952 }
953
954 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
955 Stream_Write_UINT64(s, pdu->cacheKey); /* cacheKey (8 bytes) */
956 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
957
958 /* rectSrc (8 bytes ) */
959 if ((error = rdpgfx_write_rect16(s, &(pdu->rectSrc))))
960 {
961 WLog_ERR(TAG, "rdpgfx_write_rect16 failed with error %" PRIu32 "!", error);
962 goto error;
963 }
964
965 return rdpgfx_server_single_packet_send(context, s);
966 error:
967 Stream_Free(s, TRUE);
968 return error;
969 }
970
971 /**
972 * Function description
973 *
974 * @return 0 on success, otherwise a Win32 error code
975 */
rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext * context,const RDPGFX_CACHE_TO_SURFACE_PDU * pdu)976 static UINT rdpgfx_send_cache_to_surface_pdu(RdpgfxServerContext* context,
977 const RDPGFX_CACHE_TO_SURFACE_PDU* pdu)
978 {
979 UINT error = CHANNEL_RC_OK;
980 UINT16 index;
981 RDPGFX_POINT16* destPt;
982 wStream* s =
983 rdpgfx_server_single_packet_new(RDPGFX_CMDID_CACHETOSURFACE, 6 + 4 * pdu->destPtsCount);
984
985 if (!s)
986 {
987 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
988 return CHANNEL_RC_NO_MEMORY;
989 }
990
991 Stream_Write_UINT16(s, pdu->cacheSlot); /* cacheSlot (2 bytes) */
992 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
993 Stream_Write_UINT16(s, pdu->destPtsCount); /* destPtsCount (2 bytes) */
994
995 for (index = 0; index < pdu->destPtsCount; index++)
996 {
997 destPt = &(pdu->destPts[index]);
998
999 if ((error = rdpgfx_write_point16(s, destPt)))
1000 {
1001 WLog_ERR(TAG, "rdpgfx_write_point16 failed with error %" PRIu32 "", error);
1002 goto error;
1003 }
1004 }
1005
1006 return rdpgfx_server_single_packet_send(context, s);
1007 error:
1008 Stream_Free(s, TRUE);
1009 return error;
1010 }
1011
1012 /**
1013 * Function description
1014 *
1015 * @return 0 on success, otherwise a Win32 error code
1016 */
rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext * context,const RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU * pdu)1017 static UINT rdpgfx_send_map_surface_to_output_pdu(RdpgfxServerContext* context,
1018 const RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* pdu)
1019 {
1020 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOOUTPUT, 12);
1021
1022 if (!s)
1023 {
1024 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
1025 return CHANNEL_RC_NO_MEMORY;
1026 }
1027
1028 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1029 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1030 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1031 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1032 return rdpgfx_server_single_packet_send(context, s);
1033 }
1034
1035 /**
1036 * Function description
1037 *
1038 * @return 0 on success, otherwise a Win32 error code
1039 */
rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext * context,const RDPGFX_MAP_SURFACE_TO_WINDOW_PDU * pdu)1040 static UINT rdpgfx_send_map_surface_to_window_pdu(RdpgfxServerContext* context,
1041 const RDPGFX_MAP_SURFACE_TO_WINDOW_PDU* pdu)
1042 {
1043 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOWINDOW, 18);
1044
1045 if (!s)
1046 {
1047 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
1048 return CHANNEL_RC_NO_MEMORY;
1049 }
1050
1051 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1052 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1053 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1054 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1055 return rdpgfx_server_single_packet_send(context, s);
1056 }
1057
1058 static UINT
rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext * context,const RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU * pdu)1059 rdpgfx_send_map_surface_to_scaled_window_pdu(RdpgfxServerContext* context,
1060 const RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU* pdu)
1061 {
1062 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOSCALEDWINDOW, 26);
1063
1064 if (!s)
1065 {
1066 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
1067 return CHANNEL_RC_NO_MEMORY;
1068 }
1069
1070 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1071 Stream_Write_UINT64(s, pdu->windowId); /* windowId (8 bytes) */
1072 Stream_Write_UINT32(s, pdu->mappedWidth); /* mappedWidth (4 bytes) */
1073 Stream_Write_UINT32(s, pdu->mappedHeight); /* mappedHeight (4 bytes) */
1074 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1075 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1076 return rdpgfx_server_single_packet_send(context, s);
1077 }
1078
1079 /**
1080 * Function description
1081 *
1082 * @return 0 on success, otherwise a Win32 error code
1083 */
rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext * context,wStream * s)1084 static UINT rdpgfx_recv_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s)
1085 {
1086 RDPGFX_FRAME_ACKNOWLEDGE_PDU pdu;
1087 UINT error = CHANNEL_RC_OK;
1088
1089 if (Stream_GetRemainingLength(s) < 12)
1090 {
1091 WLog_ERR(TAG, "not enough data!");
1092 return ERROR_INVALID_DATA;
1093 }
1094
1095 Stream_Read_UINT32(s, pdu.queueDepth); /* queueDepth (4 bytes) */
1096 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1097 Stream_Read_UINT32(s, pdu.totalFramesDecoded); /* totalFramesDecoded (4 bytes) */
1098
1099 if (context)
1100 {
1101 IFCALLRET(context->FrameAcknowledge, error, context, &pdu);
1102
1103 if (error)
1104 WLog_ERR(TAG, "context->FrameAcknowledge failed with error %" PRIu32 "", error);
1105 }
1106
1107 return error;
1108 }
1109
1110 /**
1111 * Function description
1112 *
1113 * @return 0 on success, otherwise a Win32 error code
1114 */
rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext * context,wStream * s)1115 static UINT rdpgfx_recv_cache_import_offer_pdu(RdpgfxServerContext* context, wStream* s)
1116 {
1117 UINT16 index;
1118 RDPGFX_CACHE_IMPORT_OFFER_PDU pdu = { 0 };
1119 RDPGFX_CACHE_ENTRY_METADATA* cacheEntries;
1120 UINT error = CHANNEL_RC_OK;
1121
1122 if (Stream_GetRemainingLength(s) < 2)
1123 {
1124 WLog_ERR(TAG, "not enough data!");
1125 return ERROR_INVALID_DATA;
1126 }
1127
1128 /* cacheEntriesCount (2 bytes) */
1129 Stream_Read_UINT16(s, pdu.cacheEntriesCount);
1130
1131 /* 2.2.2.16 RDPGFX_CACHE_IMPORT_OFFER_PDU */
1132 if (pdu.cacheEntriesCount >= 5462)
1133 {
1134 WLog_ERR(TAG, "Invalid cacheEntriesCount: %" PRIu16 "", pdu.cacheEntriesCount);
1135 return ERROR_INVALID_DATA;
1136 }
1137
1138 if (Stream_GetRemainingLength(s) < (pdu.cacheEntriesCount * 12))
1139 {
1140 WLog_ERR(TAG, "not enough data!");
1141 return ERROR_INVALID_DATA;
1142 }
1143
1144 if (pdu.cacheEntriesCount > 0)
1145 {
1146 pdu.cacheEntries = (RDPGFX_CACHE_ENTRY_METADATA*)calloc(
1147 pdu.cacheEntriesCount, sizeof(RDPGFX_CACHE_ENTRY_METADATA));
1148
1149 if (!pdu.cacheEntries)
1150 {
1151 WLog_ERR(TAG, "calloc failed!");
1152 return CHANNEL_RC_NO_MEMORY;
1153 }
1154 }
1155
1156 for (index = 0; index < pdu.cacheEntriesCount; index++)
1157 {
1158 cacheEntries = &(pdu.cacheEntries[index]);
1159 Stream_Read_UINT64(s, cacheEntries->cacheKey); /* cacheKey (8 bytes) */
1160 Stream_Read_UINT32(s, cacheEntries->bitmapLength); /* bitmapLength (4 bytes) */
1161 }
1162
1163 if (context)
1164 {
1165 IFCALLRET(context->CacheImportOffer, error, context, &pdu);
1166
1167 if (error)
1168 WLog_ERR(TAG, "context->CacheImportOffer failed with error %" PRIu32 "", error);
1169 }
1170
1171 free(pdu.cacheEntries);
1172 return error;
1173 }
1174
1175 /**
1176 * Function description
1177 *
1178 * @return 0 on success, otherwise a Win32 error code
1179 */
rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext * context,wStream * s)1180 static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, wStream* s)
1181 {
1182 UINT16 index;
1183 RDPGFX_CAPSET* capsSets = NULL;
1184 RDPGFX_CAPS_ADVERTISE_PDU pdu = { 0 };
1185 UINT error = ERROR_INVALID_DATA;
1186
1187 if (!context)
1188 return ERROR_BAD_ARGUMENTS;
1189
1190 if (Stream_GetRemainingLength(s) < 2)
1191 {
1192 WLog_ERR(TAG, "not enough data!");
1193 return ERROR_INVALID_DATA;
1194 }
1195
1196 Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */
1197 if (pdu.capsSetCount > 0)
1198 {
1199 capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4));
1200 if (!capsSets)
1201 return ERROR_OUTOFMEMORY;
1202 }
1203
1204 pdu.capsSets = capsSets;
1205
1206 for (index = 0; index < pdu.capsSetCount; index++)
1207 {
1208 RDPGFX_CAPSET* capsSet = &(pdu.capsSets[index]);
1209
1210 if (Stream_GetRemainingLength(s) < 8)
1211 goto fail;
1212
1213 Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */
1214 Stream_Read_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */
1215
1216 if (capsSet->length >= 4)
1217 {
1218 if (Stream_GetRemainingLength(s) < 4)
1219 goto fail;
1220
1221 Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */
1222 }
1223
1224 if (!Stream_SafeSeek(s, capsSet->length))
1225 goto fail;
1226 }
1227
1228 error = ERROR_BAD_CONFIGURATION;
1229 IFCALLRET(context->CapsAdvertise, error, context, &pdu);
1230
1231 if (error)
1232 WLog_ERR(TAG, "context->CapsAdvertise failed with error %" PRIu32 "", error);
1233
1234 fail:
1235 free(capsSets);
1236 return error;
1237 }
1238
1239 /**
1240 * Function description
1241 *
1242 * @return 0 on success, otherwise a Win32 error code
1243 */
rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext * context,wStream * s)1244 static UINT rdpgfx_recv_qoe_frame_acknowledge_pdu(RdpgfxServerContext* context, wStream* s)
1245 {
1246 RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU pdu;
1247 UINT error = CHANNEL_RC_OK;
1248
1249 if (Stream_GetRemainingLength(s) < 12)
1250 {
1251 WLog_ERR(TAG, "not enough data!");
1252 return ERROR_INVALID_DATA;
1253 }
1254
1255 Stream_Read_UINT32(s, pdu.frameId); /* frameId (4 bytes) */
1256 Stream_Read_UINT32(s, pdu.timestamp); /* timestamp (4 bytes) */
1257 Stream_Read_UINT16(s, pdu.timeDiffSE); /* timeDiffSE (2 bytes) */
1258 Stream_Read_UINT16(s, pdu.timeDiffEDR); /* timeDiffEDR (2 bytes) */
1259
1260 if (context)
1261 {
1262 IFCALLRET(context->QoeFrameAcknowledge, error, context, &pdu);
1263
1264 if (error)
1265 WLog_ERR(TAG, "context->QoeFrameAcknowledge failed with error %" PRIu32 "", error);
1266 }
1267
1268 return error;
1269 }
1270
1271 static UINT
rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext * context,const RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU * pdu)1272 rdpgfx_send_map_surface_to_scaled_output_pdu(RdpgfxServerContext* context,
1273 const RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU* pdu)
1274 {
1275 wStream* s = rdpgfx_server_single_packet_new(RDPGFX_CMDID_MAPSURFACETOSCALEDOUTPUT, 20);
1276
1277 if (!s)
1278 {
1279 WLog_ERR(TAG, "rdpgfx_server_single_packet_new failed!");
1280 return CHANNEL_RC_NO_MEMORY;
1281 }
1282
1283 Stream_Write_UINT16(s, pdu->surfaceId); /* surfaceId (2 bytes) */
1284 Stream_Write_UINT16(s, 0); /* reserved (2 bytes). Must be 0 */
1285 Stream_Write_UINT32(s, pdu->outputOriginX); /* outputOriginX (4 bytes) */
1286 Stream_Write_UINT32(s, pdu->outputOriginY); /* outputOriginY (4 bytes) */
1287 Stream_Write_UINT32(s, pdu->targetWidth); /* targetWidth (4 bytes) */
1288 Stream_Write_UINT32(s, pdu->targetHeight); /* targetHeight (4 bytes) */
1289 return rdpgfx_server_single_packet_send(context, s);
1290 }
1291
1292 /**
1293 * Function description
1294 *
1295 * @return 0 on success, otherwise a Win32 error code
1296 */
rdpgfx_server_receive_pdu(RdpgfxServerContext * context,wStream * s)1297 static UINT rdpgfx_server_receive_pdu(RdpgfxServerContext* context, wStream* s)
1298 {
1299 size_t beg, end;
1300 RDPGFX_HEADER header;
1301 UINT error = CHANNEL_RC_OK;
1302 beg = Stream_GetPosition(s);
1303
1304 if ((error = rdpgfx_read_header(s, &header)))
1305 {
1306 WLog_ERR(TAG, "rdpgfx_read_header failed with error %" PRIu32 "!", error);
1307 return error;
1308 }
1309
1310 #ifdef WITH_DEBUG_RDPGFX
1311 WLog_DBG(TAG, "cmdId: %s (0x%04" PRIX16 ") flags: 0x%04" PRIX16 " pduLength: %" PRIu32 "",
1312 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId, header.flags, header.pduLength);
1313 #endif
1314
1315 switch (header.cmdId)
1316 {
1317 case RDPGFX_CMDID_FRAMEACKNOWLEDGE:
1318 if ((error = rdpgfx_recv_frame_acknowledge_pdu(context, s)))
1319 WLog_ERR(TAG,
1320 "rdpgfx_recv_frame_acknowledge_pdu "
1321 "failed with error %" PRIu32 "!",
1322 error);
1323
1324 break;
1325
1326 case RDPGFX_CMDID_CACHEIMPORTOFFER:
1327 if ((error = rdpgfx_recv_cache_import_offer_pdu(context, s)))
1328 WLog_ERR(TAG,
1329 "rdpgfx_recv_cache_import_offer_pdu "
1330 "failed with error %" PRIu32 "!",
1331 error);
1332
1333 break;
1334
1335 case RDPGFX_CMDID_CAPSADVERTISE:
1336 if ((error = rdpgfx_recv_caps_advertise_pdu(context, s)))
1337 WLog_ERR(TAG,
1338 "rdpgfx_recv_caps_advertise_pdu "
1339 "failed with error %" PRIu32 "!",
1340 error);
1341
1342 break;
1343
1344 case RDPGFX_CMDID_QOEFRAMEACKNOWLEDGE:
1345 if ((error = rdpgfx_recv_qoe_frame_acknowledge_pdu(context, s)))
1346 WLog_ERR(TAG,
1347 "rdpgfx_recv_qoe_frame_acknowledge_pdu "
1348 "failed with error %" PRIu32 "!",
1349 error);
1350
1351 break;
1352
1353 default:
1354 error = CHANNEL_RC_BAD_PROC;
1355 break;
1356 }
1357
1358 if (error)
1359 {
1360 WLog_ERR(TAG, "Error while parsing GFX cmdId: %s (0x%04" PRIX16 ")",
1361 rdpgfx_get_cmd_id_string(header.cmdId), header.cmdId);
1362 return error;
1363 }
1364
1365 end = Stream_GetPosition(s);
1366
1367 if (end != (beg + header.pduLength))
1368 {
1369 WLog_ERR(TAG, "Unexpected gfx pdu end: Actual: %d, Expected: %" PRIu32 "", end,
1370 (beg + header.pduLength));
1371 Stream_SetPosition(s, (beg + header.pduLength));
1372 }
1373
1374 return error;
1375 }
1376
rdpgfx_server_thread_func(LPVOID arg)1377 static DWORD WINAPI rdpgfx_server_thread_func(LPVOID arg)
1378 {
1379 RdpgfxServerContext* context = (RdpgfxServerContext*)arg;
1380 RdpgfxServerPrivate* priv = context->priv;
1381 DWORD status;
1382 DWORD nCount;
1383 void* buffer;
1384 HANDLE events[8];
1385 UINT error = CHANNEL_RC_OK;
1386 buffer = NULL;
1387 nCount = 0;
1388 events[nCount++] = priv->stopEvent;
1389 events[nCount++] = priv->channelEvent;
1390
1391 /* Main virtual channel loop. RDPGFX do not need version negotiation */
1392 while (TRUE)
1393 {
1394 status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
1395
1396 if (status == WAIT_FAILED)
1397 {
1398 error = GetLastError();
1399 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error);
1400 break;
1401 }
1402
1403 /* Stop Event */
1404 if (status == WAIT_OBJECT_0)
1405 break;
1406
1407 if ((error = rdpgfx_server_handle_messages(context)))
1408 {
1409 WLog_ERR(TAG, "rdpgfx_server_handle_messages failed with error %" PRIu32 "", error);
1410 break;
1411 }
1412 }
1413
1414 if (error && context->rdpcontext)
1415 setChannelError(context->rdpcontext, error, "rdpgfx_server_thread_func reported an error");
1416
1417 ExitThread(error);
1418 return error;
1419 }
1420
rdpgfx_server_open(RdpgfxServerContext * context)1421 static BOOL rdpgfx_server_open(RdpgfxServerContext* context)
1422 {
1423 RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*)context->priv;
1424 void* buffer = NULL;
1425
1426 if (!priv->isOpened)
1427 {
1428 PULONG pSessionId = NULL;
1429 DWORD BytesReturned = 0;
1430 priv->SessionId = WTS_CURRENT_SESSION;
1431
1432 if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId,
1433 (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
1434 {
1435 WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
1436 return FALSE;
1437 }
1438
1439 priv->SessionId = (DWORD)*pSessionId;
1440 WTSFreeMemory(pSessionId);
1441 priv->rdpgfx_channel = WTSVirtualChannelOpenEx(priv->SessionId, RDPGFX_DVC_CHANNEL_NAME,
1442 WTS_CHANNEL_OPTION_DYNAMIC);
1443
1444 if (!priv->rdpgfx_channel)
1445 {
1446 WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!");
1447 return FALSE;
1448 }
1449
1450 /* Query for channel event handle */
1451 if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer,
1452 &BytesReturned) ||
1453 (BytesReturned != sizeof(HANDLE)))
1454 {
1455 WLog_ERR(TAG,
1456 "WTSVirtualChannelQuery failed "
1457 "or invalid returned size(%" PRIu32 ")",
1458 BytesReturned);
1459
1460 if (buffer)
1461 WTSFreeMemory(buffer);
1462
1463 goto out_close;
1464 }
1465
1466 CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE));
1467 WTSFreeMemory(buffer);
1468
1469 if (!(priv->zgfx = zgfx_context_new(TRUE)))
1470 {
1471 WLog_ERR(TAG, "Create zgfx context failed!");
1472 goto out_close;
1473 }
1474
1475 if (priv->ownThread)
1476 {
1477 if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
1478 {
1479 WLog_ERR(TAG, "CreateEvent failed!");
1480 goto out_zgfx;
1481 }
1482
1483 if (!(priv->thread =
1484 CreateThread(NULL, 0, rdpgfx_server_thread_func, (void*)context, 0, NULL)))
1485 {
1486 WLog_ERR(TAG, "CreateThread failed!");
1487 goto out_stopEvent;
1488 }
1489 }
1490
1491 priv->isOpened = TRUE;
1492 priv->isReady = FALSE;
1493 return TRUE;
1494 }
1495
1496 WLog_ERR(TAG, "RDPGFX channel is already opened!");
1497 return FALSE;
1498 out_stopEvent:
1499 CloseHandle(priv->stopEvent);
1500 priv->stopEvent = NULL;
1501 out_zgfx:
1502 zgfx_context_free(priv->zgfx);
1503 priv->zgfx = NULL;
1504 out_close:
1505 WTSVirtualChannelClose(priv->rdpgfx_channel);
1506 priv->rdpgfx_channel = NULL;
1507 priv->channelEvent = NULL;
1508 return FALSE;
1509 }
1510
rdpgfx_server_close(RdpgfxServerContext * context)1511 static BOOL rdpgfx_server_close(RdpgfxServerContext* context)
1512 {
1513 RdpgfxServerPrivate* priv = (RdpgfxServerPrivate*)context->priv;
1514
1515 if (priv->ownThread && priv->thread)
1516 {
1517 SetEvent(priv->stopEvent);
1518
1519 if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED)
1520 {
1521 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", GetLastError());
1522 return FALSE;
1523 }
1524
1525 CloseHandle(priv->thread);
1526 CloseHandle(priv->stopEvent);
1527 priv->thread = NULL;
1528 priv->stopEvent = NULL;
1529 }
1530
1531 zgfx_context_free(priv->zgfx);
1532 priv->zgfx = NULL;
1533
1534 if (priv->rdpgfx_channel)
1535 {
1536 WTSVirtualChannelClose(priv->rdpgfx_channel);
1537 priv->rdpgfx_channel = NULL;
1538 }
1539
1540 priv->channelEvent = NULL;
1541 priv->isOpened = FALSE;
1542 priv->isReady = FALSE;
1543 return TRUE;
1544 }
1545
rdpgfx_server_context_new(HANDLE vcm)1546 RdpgfxServerContext* rdpgfx_server_context_new(HANDLE vcm)
1547 {
1548 RdpgfxServerContext* context;
1549 RdpgfxServerPrivate* priv;
1550 context = (RdpgfxServerContext*)calloc(1, sizeof(RdpgfxServerContext));
1551
1552 if (!context)
1553 {
1554 WLog_ERR(TAG, "calloc failed!");
1555 return NULL;
1556 }
1557
1558 context->vcm = vcm;
1559 context->Open = rdpgfx_server_open;
1560 context->Close = rdpgfx_server_close;
1561 context->ResetGraphics = rdpgfx_send_reset_graphics_pdu;
1562 context->StartFrame = rdpgfx_send_start_frame_pdu;
1563 context->EndFrame = rdpgfx_send_end_frame_pdu;
1564 context->SurfaceCommand = rdpgfx_send_surface_command;
1565 context->SurfaceFrameCommand = rdpgfx_send_surface_frame_command;
1566 context->DeleteEncodingContext = rdpgfx_send_delete_encoding_context_pdu;
1567 context->CreateSurface = rdpgfx_send_create_surface_pdu;
1568 context->DeleteSurface = rdpgfx_send_delete_surface_pdu;
1569 context->SolidFill = rdpgfx_send_solid_fill_pdu;
1570 context->SurfaceToSurface = rdpgfx_send_surface_to_surface_pdu;
1571 context->SurfaceToCache = rdpgfx_send_surface_to_cache_pdu;
1572 context->CacheToSurface = rdpgfx_send_cache_to_surface_pdu;
1573 context->CacheImportOffer = NULL;
1574 context->CacheImportReply = rdpgfx_send_cache_import_reply_pdu;
1575 context->EvictCacheEntry = rdpgfx_send_evict_cache_entry_pdu;
1576 context->MapSurfaceToOutput = rdpgfx_send_map_surface_to_output_pdu;
1577 context->MapSurfaceToWindow = rdpgfx_send_map_surface_to_window_pdu;
1578 context->MapSurfaceToScaledOutput = rdpgfx_send_map_surface_to_scaled_output_pdu;
1579 context->MapSurfaceToScaledWindow = rdpgfx_send_map_surface_to_scaled_window_pdu;
1580 context->CapsAdvertise = NULL;
1581 context->CapsConfirm = rdpgfx_send_caps_confirm_pdu;
1582 context->FrameAcknowledge = NULL;
1583 context->QoeFrameAcknowledge = NULL;
1584 context->priv = priv = (RdpgfxServerPrivate*)calloc(1, sizeof(RdpgfxServerPrivate));
1585
1586 if (!priv)
1587 {
1588 WLog_ERR(TAG, "calloc failed!");
1589 goto out_free;
1590 }
1591
1592 /* Create shared input stream */
1593 priv->input_stream = Stream_New(NULL, 4);
1594
1595 if (!priv->input_stream)
1596 {
1597 WLog_ERR(TAG, "Stream_New failed!");
1598 goto out_free_priv;
1599 }
1600
1601 priv->isOpened = FALSE;
1602 priv->isReady = FALSE;
1603 priv->ownThread = TRUE;
1604 return (RdpgfxServerContext*)context;
1605 out_free_priv:
1606 free(context->priv);
1607 out_free:
1608 free(context);
1609 return NULL;
1610 }
1611
rdpgfx_server_context_free(RdpgfxServerContext * context)1612 void rdpgfx_server_context_free(RdpgfxServerContext* context)
1613 {
1614 rdpgfx_server_close(context);
1615
1616 if (context->priv)
1617 Stream_Free(context->priv->input_stream, TRUE);
1618
1619 free(context->priv);
1620 free(context);
1621 }
1622
rdpgfx_server_get_event_handle(RdpgfxServerContext * context)1623 HANDLE rdpgfx_server_get_event_handle(RdpgfxServerContext* context)
1624 {
1625 return context->priv->channelEvent;
1626 }
1627
1628 /*
1629 * Handle rpdgfx messages - server side
1630 *
1631 * @param Server side context
1632 *
1633 * @return 0 on success
1634 * ERROR_NO_DATA if no data could be read this time
1635 * otherwise a Win32 error code
1636 */
rdpgfx_server_handle_messages(RdpgfxServerContext * context)1637 UINT rdpgfx_server_handle_messages(RdpgfxServerContext* context)
1638 {
1639 DWORD BytesReturned;
1640 void* buffer;
1641 UINT ret = CHANNEL_RC_OK;
1642 RdpgfxServerPrivate* priv = context->priv;
1643 wStream* s = priv->input_stream;
1644
1645 /* Check whether the dynamic channel is ready */
1646 if (!priv->isReady)
1647 {
1648 if (WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualChannelReady, &buffer,
1649 &BytesReturned) == FALSE)
1650 {
1651 if (GetLastError() == ERROR_NO_DATA)
1652 return ERROR_NO_DATA;
1653
1654 WLog_ERR(TAG, "WTSVirtualChannelQuery failed");
1655 return ERROR_INTERNAL_ERROR;
1656 }
1657
1658 priv->isReady = *((BOOL*)buffer);
1659 WTSFreeMemory(buffer);
1660 }
1661
1662 /* Consume channel event only after the gfx dynamic channel is ready */
1663 if (priv->isReady)
1664 {
1665 Stream_SetPosition(s, 0);
1666
1667 if (!WTSVirtualChannelRead(priv->rdpgfx_channel, 0, NULL, 0, &BytesReturned))
1668 {
1669 if (GetLastError() == ERROR_NO_DATA)
1670 return ERROR_NO_DATA;
1671
1672 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
1673 return ERROR_INTERNAL_ERROR;
1674 }
1675
1676 if (BytesReturned < 1)
1677 return CHANNEL_RC_OK;
1678
1679 if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
1680 {
1681 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
1682 return CHANNEL_RC_NO_MEMORY;
1683 }
1684
1685 if (WTSVirtualChannelRead(priv->rdpgfx_channel, 0, (PCHAR)Stream_Buffer(s),
1686 Stream_Capacity(s), &BytesReturned) == FALSE)
1687 {
1688 WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
1689 return ERROR_INTERNAL_ERROR;
1690 }
1691
1692 Stream_SetLength(s, BytesReturned);
1693 Stream_SetPosition(s, 0);
1694
1695 while (Stream_GetPosition(s) < Stream_Length(s))
1696 {
1697 if ((ret = rdpgfx_server_receive_pdu(context, s)))
1698 {
1699 WLog_ERR(TAG,
1700 "rdpgfx_server_receive_pdu "
1701 "failed with error %" PRIu32 "!",
1702 ret);
1703 return ret;
1704 }
1705 }
1706 }
1707
1708 return ret;
1709 }
1710