FreeRDP
surface.c
1 
20 #include <freerdp/config.h>
21 
22 #include "settings.h"
23 
24 #include <winpr/assert.h>
25 #include <winpr/cast.h>
26 
27 #include <freerdp/utils/pcap.h>
28 #include <freerdp/log.h>
29 
30 #include "../cache/cache.h"
31 #include "surface.h"
32 
33 #define TAG FREERDP_TAG("core.surface")
34 
35 static BOOL update_recv_surfcmd_bitmap_header_ex(wStream* s, TS_COMPRESSED_BITMAP_HEADER_EX* header)
36 {
37  if (!s || !header)
38  return FALSE;
39 
40  if (!Stream_CheckAndLogRequiredLength(TAG, s, 24))
41  return FALSE;
42 
43  Stream_Read_UINT32(s, header->highUniqueId);
44  Stream_Read_UINT32(s, header->lowUniqueId);
45  Stream_Read_UINT64(s, header->tmMilliseconds);
46  Stream_Read_UINT64(s, header->tmSeconds);
47  return TRUE;
48 }
49 
50 static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp)
51 {
52  if (!s || !bmp)
53  return FALSE;
54 
55  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
56  return FALSE;
57 
58  Stream_Read_UINT8(s, bmp->bpp);
59  Stream_Read_UINT8(s, bmp->flags);
60  Stream_Seek(s, 1); /* reserved */
61  Stream_Read_UINT8(s, bmp->codecID);
62  Stream_Read_UINT16(s, bmp->width);
63  Stream_Read_UINT16(s, bmp->height);
64  Stream_Read_UINT32(s, bmp->bitmapDataLength);
65 
66  if ((bmp->width == 0) || (bmp->height == 0))
67  {
68  WLog_ERR(TAG, "invalid size value width=%" PRIu16 ", height=%" PRIu16, bmp->width,
69  bmp->height);
70  return FALSE;
71  }
72 
73  if ((bmp->bpp < 1) || (bmp->bpp > 32))
74  {
75  WLog_ERR(TAG, "invalid bpp value %" PRIu32 "", bmp->bpp);
76  return FALSE;
77  }
78 
79  if (bmp->flags & EX_COMPRESSED_BITMAP_HEADER_PRESENT)
80  {
81  if (!update_recv_surfcmd_bitmap_header_ex(s, &bmp->exBitmapDataHeader))
82  return FALSE;
83  }
84 
85  bmp->bitmapData = Stream_Pointer(s);
86  if (!Stream_SafeSeek(s, bmp->bitmapDataLength))
87  {
88  WLog_ERR(TAG, "expected bitmapDataLength %" PRIu32 ", not enough data",
89  bmp->bitmapDataLength);
90  return FALSE;
91  }
92  return TRUE;
93 }
94 
95 static BOOL update_recv_surfcmd_is_rect_valid(const rdpContext* context,
96  const SURFACE_BITS_COMMAND* cmd)
97 {
98  WINPR_ASSERT(context);
99  WINPR_ASSERT(context->settings);
100  WINPR_ASSERT(cmd);
101 
102  /* We need a rectangle with left/top being smaller than right/bottom.
103  * Also do not allow empty rectangles. */
104  if ((cmd->destTop >= cmd->destBottom) || (cmd->destLeft >= cmd->destRight))
105  {
106  WLog_WARN(TAG,
107  "Empty surface bits command rectangle: %" PRIu16 "x%" PRIu16 "-%" PRIu16
108  "x%" PRIu16,
109  cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom);
110  return FALSE;
111  }
112 
113  /* The rectangle needs to fit into our session size */
114  if ((cmd->destRight > context->settings->DesktopWidth) ||
115  (cmd->destBottom > context->settings->DesktopHeight))
116  {
117  WLog_WARN(TAG,
118  "Invalid surface bits command rectangle: %" PRIu16 "x%" PRIu16 "-%" PRIu16
119  "x%" PRIu16 " does not fit %" PRIu32 "x%" PRIu32,
120  cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom,
121  context->settings->DesktopWidth, context->settings->DesktopHeight);
122  return FALSE;
123  }
124 
125  return TRUE;
126 }
127 
128 static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT16 cmdType)
129 {
130  BOOL rc = FALSE;
131  SURFACE_BITS_COMMAND cmd = { 0 };
132 
133  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
134  goto fail;
135 
136  cmd.cmdType = cmdType;
137  Stream_Read_UINT16(s, cmd.destLeft);
138  Stream_Read_UINT16(s, cmd.destTop);
139  Stream_Read_UINT16(s, cmd.destRight);
140  Stream_Read_UINT16(s, cmd.destBottom);
141 
142  if (!update_recv_surfcmd_is_rect_valid(update->context, &cmd))
143  goto fail;
144 
145  if (!update_recv_surfcmd_bitmap_ex(s, &cmd.bmp))
146  goto fail;
147 
148  if (!IFCALLRESULT(TRUE, update->SurfaceBits, update->context, &cmd))
149  {
150  WLog_DBG(TAG, "update->SurfaceBits implementation failed");
151  goto fail;
152  }
153 
154  rc = TRUE;
155 fail:
156  return rc;
157 }
158 
159 static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s)
160 {
161  SURFACE_FRAME_MARKER marker = { 0 };
162  rdp_update_internal* up = update_cast(update);
163 
164  WINPR_ASSERT(s);
165 
166  if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
167  return FALSE;
168 
169  Stream_Read_UINT16(s, marker.frameAction);
170  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
171  WLog_WARN(TAG,
172  "[SERVER-BUG]: got %" PRIuz ", expected %" PRIuz
173  " bytes. [MS-RDPBCGR] 2.2.9.2.3 Frame Marker Command (TS_FRAME_MARKER) is "
174  "missing frameId, ignoring",
175  Stream_GetRemainingLength(s), 4);
176  else
177  Stream_Read_UINT32(s, marker.frameId);
178  WLog_Print(up->log, WLOG_DEBUG, "SurfaceFrameMarker: action: %s (%" PRIu32 ") id: %" PRIu32 "",
179  (!marker.frameAction) ? "Begin" : "End", marker.frameAction, marker.frameId);
180 
181  if (!update->SurfaceFrameMarker)
182  {
183  WINPR_ASSERT(update->context);
184  if (freerdp_settings_get_bool(update->context->settings, FreeRDP_DeactivateClientDecoding))
185  return TRUE;
186  WLog_ERR(TAG, "Missing callback update->SurfaceFrameMarker");
187  return FALSE;
188  }
189 
190  if (!update->SurfaceFrameMarker(update->context, &marker))
191  {
192  WLog_DBG(TAG, "update->SurfaceFrameMarker implementation failed");
193  return FALSE;
194  }
195 
196  return TRUE;
197 }
198 
199 int update_recv_surfcmds(rdpUpdate* update, wStream* s)
200 {
201  UINT16 cmdType = 0;
202  rdp_update_internal* up = update_cast(update);
203 
204  WINPR_ASSERT(s);
205 
206  while (Stream_GetRemainingLength(s) >= 2)
207  {
208  const size_t start = Stream_GetPosition(s);
209  const BYTE* mark = Stream_ConstPointer(s);
210 
211  Stream_Read_UINT16(s, cmdType);
212 
213  switch (cmdType)
214  {
215  case CMDTYPE_SET_SURFACE_BITS:
216  case CMDTYPE_STREAM_SURFACE_BITS:
217  if (!update_recv_surfcmd_surface_bits(update, s, cmdType))
218  return -1;
219 
220  break;
221 
222  case CMDTYPE_FRAME_MARKER:
223  if (!update_recv_surfcmd_frame_marker(update, s))
224  return -1;
225 
226  break;
227 
228  default:
229  WLog_ERR(TAG, "unknown cmdType 0x%04" PRIX16 "", cmdType);
230  return -1;
231  }
232 
233  if (up->dump_rfx)
234  {
235  const size_t size = Stream_GetPosition(s) - start;
236  /* TODO: treat return values */
237  pcap_add_record(up->pcap_rfx, mark, size);
238  pcap_flush(up->pcap_rfx);
239  }
240  }
241 
242  return 0;
243 }
244 
245 static BOOL update_write_surfcmd_bitmap_header_ex(wStream* s,
246  const TS_COMPRESSED_BITMAP_HEADER_EX* header)
247 {
248  if (!s || !header)
249  return FALSE;
250 
251  if (!Stream_EnsureRemainingCapacity(s, 24))
252  return FALSE;
253 
254  Stream_Write_UINT32(s, header->highUniqueId);
255  Stream_Write_UINT32(s, header->lowUniqueId);
256  Stream_Write_UINT64(s, header->tmMilliseconds);
257  Stream_Write_UINT64(s, header->tmSeconds);
258  return TRUE;
259 }
260 
261 static BOOL update_write_surfcmd_bitmap_ex(wStream* s, const TS_BITMAP_DATA_EX* bmp)
262 {
263  if (!s || !bmp)
264  return FALSE;
265 
266  if (!Stream_EnsureRemainingCapacity(s, 12))
267  return FALSE;
268 
269  if (bmp->codecID > UINT8_MAX)
270  {
271  WLog_ERR(TAG, "Invalid TS_BITMAP_DATA_EX::codecID=0x%04" PRIx16 "", bmp->codecID);
272  return FALSE;
273  }
274  Stream_Write_UINT8(s, bmp->bpp);
275  Stream_Write_UINT8(s, bmp->flags);
276  Stream_Write_UINT8(s, 0); /* reserved1, reserved2 */
277  Stream_Write_UINT8(s, (UINT8)bmp->codecID);
278  Stream_Write_UINT16(s, bmp->width);
279  Stream_Write_UINT16(s, bmp->height);
280  Stream_Write_UINT32(s, bmp->bitmapDataLength);
281 
282  if (bmp->flags & EX_COMPRESSED_BITMAP_HEADER_PRESENT)
283  {
284  if (!update_write_surfcmd_bitmap_header_ex(s, &bmp->exBitmapDataHeader))
285  return FALSE;
286  }
287 
288  if (!Stream_EnsureRemainingCapacity(s, bmp->bitmapDataLength))
289  return FALSE;
290 
291  Stream_Write(s, bmp->bitmapData, bmp->bitmapDataLength);
292  return TRUE;
293 }
294 
295 BOOL update_write_surfcmd_surface_bits(wStream* s, const SURFACE_BITS_COMMAND* cmd)
296 {
297  if (!Stream_EnsureRemainingCapacity(s, SURFCMD_SURFACE_BITS_HEADER_LENGTH))
298  return FALSE;
299 
300  WINPR_ASSERT(cmd->cmdType <= UINT16_MAX);
301  UINT16 cmdType = (UINT16)cmd->cmdType;
302  switch (cmdType)
303  {
304  case CMDTYPE_SET_SURFACE_BITS:
305  case CMDTYPE_STREAM_SURFACE_BITS:
306  break;
307  default:
308  WLog_WARN(TAG,
309  "SURFACE_BITS_COMMAND->cmdType 0x%04" PRIx16
310  " not allowed, correcting to 0x%04" PRIx16,
311  cmdType, CMDTYPE_STREAM_SURFACE_BITS);
312  cmdType = CMDTYPE_STREAM_SURFACE_BITS;
313  break;
314  }
315 
316  Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmdType));
317  Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->destLeft));
318  Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->destTop));
319  Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->destRight));
320  Stream_Write_UINT16(s, WINPR_ASSERTING_INT_CAST(uint16_t, cmd->destBottom));
321  return update_write_surfcmd_bitmap_ex(s, &cmd->bmp);
322 }
323 
324 BOOL update_write_surfcmd_frame_marker(wStream* s, UINT16 frameAction, UINT32 frameId)
325 {
326  if (!Stream_EnsureRemainingCapacity(s, SURFCMD_FRAME_MARKER_LENGTH))
327  return FALSE;
328 
329  Stream_Write_UINT16(s, CMDTYPE_FRAME_MARKER);
330  Stream_Write_UINT16(s, frameAction);
331  Stream_Write_UINT32(s, frameId);
332  return TRUE;
333 }
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.