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