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