~ubuntu-branches/ubuntu/raring/freerdp/raring-proposed

« back to all changes in this revision

Viewing changes to libfreerdp-core/fastpath.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt, Jeremy Bicha, Jean-Louis Dupond, Martin Pitt
  • Date: 2012-01-31 10:02:14 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120131100214-jaok3uwvni7sqxth
Tags: 1.0.0-0git1
Upload current Debian packaging git to get this rolling for precise.

[ Jeremy Bicha ]
* New upstream release. Closes: #647498.
* Updated symbols and bumped soname
* debian/control:
  - Added new build dependencies
  - Bump Standards-Version to 3.9.2
* debian/source/format: Set to 3.0 (quilt)
* debian/rules: Turn on strict symbols checking
* debian/watch: Watch github

[ Jean-Louis Dupond ]
* debian/control: Updated homepage
* debian/copyright: Reflect upstream switch to the Apache license

[ Martin Pitt ]
* debian/libfreerdp0.symbols: Fix version number, should
  be 1.0~beta5, not 1.0-beta5.
* debian/control: Add libavcodec-dev build dependency, upstream build system
  checks for that. Thanks Jean-Louis Dupond!

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * FreeRDP: A Remote Desktop Protocol Client
 
3
 * Fast Path
 
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 <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <string.h>
 
23
#include <freerdp/api.h>
 
24
#include <freerdp/utils/stream.h>
 
25
 
 
26
#include "orders.h"
 
27
#include "update.h"
 
28
#include "surface.h"
 
29
 
 
30
#include "fastpath.h"
 
31
 
 
32
/**
 
33
 * Fast-Path packet format is defined in [MS-RDPBCGR] 2.2.9.1.2, which revises
 
34
 * server output packets from the first byte with the goal of improving
 
35
 * bandwidth.
 
36
 * 
 
37
 * Slow-Path packet always starts with TPKT header, which has the first
 
38
 * byte 0x03, while Fast-Path packet starts with 2 zero bits in the first
 
39
 * two less significant bits of the first byte.
 
40
 */
 
41
 
 
42
#define FASTPATH_MAX_PACKET_SIZE 0x3FFF
 
43
 
 
44
/**
 
45
 * Read a Fast-Path packet header.\n
 
46
 * @param s stream
 
47
 * @param encryptionFlags
 
48
 * @return length
 
49
 */
 
50
 
 
51
uint16 fastpath_read_header(rdpFastPath* fastpath, STREAM* s)
 
52
{
 
53
        uint8 header;
 
54
        uint16 length;
 
55
        uint8 t;
 
56
 
 
57
        stream_read_uint8(s, header);
 
58
 
 
59
        if (fastpath != NULL)
 
60
        {
 
61
                fastpath->encryptionFlags = (header & 0xC0) >> 6;
 
62
                fastpath->numberEvents = (header & 0x3C) >> 2;
 
63
        }
 
64
 
 
65
        stream_read_uint8(s, length); /* length1 */
 
66
        /* If most significant bit is not set, length2 is not presented. */
 
67
        if ((length & 0x80))
 
68
        {
 
69
                length &= 0x7F;
 
70
                length <<= 8;
 
71
                stream_read_uint8(s, t);
 
72
                length += t;
 
73
        }
 
74
 
 
75
        return length;
 
76
}
 
77
 
 
78
INLINE void fastpath_read_update_header(STREAM* s, uint8* updateCode, uint8* fragmentation, uint8* compression)
 
79
{
 
80
        uint8 updateHeader;
 
81
 
 
82
        stream_read_uint8(s, updateHeader);
 
83
        *updateCode = updateHeader & 0x0F;
 
84
        *fragmentation = (updateHeader >> 4) & 0x03;
 
85
        *compression = (updateHeader >> 6) & 0x03;
 
86
}
 
87
 
 
88
INLINE void fastpath_write_update_header(STREAM* s, uint8 updateCode, uint8 fragmentation, uint8 compression)
 
89
{
 
90
        uint8 updateHeader = 0;
 
91
 
 
92
        updateHeader |= updateCode & 0x0F;
 
93
        updateHeader |= (fragmentation & 0x03) << 4;
 
94
        updateHeader |= (compression & 0x03) << 6;
 
95
        stream_write_uint8(s, updateHeader);
 
96
}
 
97
 
 
98
uint16 fastpath_read_header_rdp(rdpFastPath* fastpath, STREAM* s)
 
99
{
 
100
        uint8 header;
 
101
        uint16 length;
 
102
        uint8 t;
 
103
        uint16 hs;
 
104
 
 
105
        hs = 2;
 
106
        stream_read_uint8(s, header);
 
107
 
 
108
        if (fastpath != NULL)
 
109
        {
 
110
                fastpath->encryptionFlags = (header & 0xC0) >> 6;
 
111
                fastpath->numberEvents = (header & 0x3C) >> 2;
 
112
        }
 
113
 
 
114
        stream_read_uint8(s, length); /* length1 */
 
115
        /* If most significant bit is not set, length2 is not presented. */
 
116
        if ((length & 0x80))
 
117
        {
 
118
                hs++;
 
119
                length &= 0x7F;
 
120
                length <<= 8;
 
121
                stream_read_uint8(s, t);
 
122
                length += t;
 
123
        }
 
124
 
 
125
        return length - hs;
 
126
}
 
127
 
 
128
static void fastpath_recv_orders(rdpFastPath* fastpath, STREAM* s)
 
129
{
 
130
        rdpUpdate* update = fastpath->rdp->update;
 
131
        uint16 numberOrders;
 
132
 
 
133
        stream_read_uint16(s, numberOrders); /* numberOrders (2 bytes) */
 
134
 
 
135
        while (numberOrders > 0)
 
136
        {
 
137
                update_recv_order(update, s);
 
138
                numberOrders--;
 
139
        }
 
140
}
 
141
 
 
142
static void fastpath_recv_update_common(rdpFastPath* fastpath, STREAM* s)
 
143
{
 
144
        uint16 updateType;
 
145
        rdpUpdate* update = fastpath->rdp->update;
 
146
        rdpContext* context = update->context;
 
147
 
 
148
        stream_read_uint16(s, updateType); /* updateType (2 bytes) */
 
149
 
 
150
        switch (updateType)
 
151
        {
 
152
                case UPDATE_TYPE_BITMAP:
 
153
                        update_read_bitmap(update, s, &update->bitmap_update);
 
154
                        IFCALL(update->BitmapUpdate, context, &update->bitmap_update);
 
155
                        break;
 
156
 
 
157
                case UPDATE_TYPE_PALETTE:
 
158
                        update_read_palette(update, s, &update->palette_update);
 
159
                        IFCALL(update->Palette, context, &update->palette_update);
 
160
                        break;
 
161
        }
 
162
}
 
163
 
 
164
static void fastpath_recv_update_synchronize(rdpFastPath* fastpath, STREAM* s)
 
165
{
 
166
        stream_seek_uint16(s); /* size (2 bytes), must be set to zero */
 
167
}
 
168
 
 
169
static void fastpath_recv_update(rdpFastPath* fastpath, uint8 updateCode, uint32 size, STREAM* s)
 
170
{
 
171
        rdpUpdate* update = fastpath->rdp->update;
 
172
        rdpContext* context = fastpath->rdp->update->context;
 
173
        rdpPointerUpdate* pointer = update->pointer;
 
174
 
 
175
        switch (updateCode)
 
176
        {
 
177
                case FASTPATH_UPDATETYPE_ORDERS:
 
178
                        fastpath_recv_orders(fastpath, s);
 
179
                        break;
 
180
 
 
181
                case FASTPATH_UPDATETYPE_BITMAP:
 
182
                case FASTPATH_UPDATETYPE_PALETTE:
 
183
                        fastpath_recv_update_common(fastpath, s);
 
184
                        break;
 
185
 
 
186
                case FASTPATH_UPDATETYPE_SYNCHRONIZE:
 
187
                        fastpath_recv_update_synchronize(fastpath, s);
 
188
                        IFCALL(update->Synchronize, context);
 
189
                        break;
 
190
 
 
191
                case FASTPATH_UPDATETYPE_SURFCMDS:
 
192
                        update_recv_surfcmds(update, size, s);
 
193
                        break;
 
194
 
 
195
                case FASTPATH_UPDATETYPE_PTR_NULL:
 
196
                        pointer->pointer_system.type = SYSPTR_NULL;
 
197
                        IFCALL(pointer->PointerSystem, context, &pointer->pointer_system);
 
198
                        break;
 
199
 
 
200
                case FASTPATH_UPDATETYPE_PTR_DEFAULT:
 
201
                        update->pointer->pointer_system.type = SYSPTR_DEFAULT;
 
202
                        IFCALL(pointer->PointerSystem, context, &pointer->pointer_system);
 
203
                        break;
 
204
 
 
205
                case FASTPATH_UPDATETYPE_PTR_POSITION:
 
206
                        update_read_pointer_position(s, &pointer->pointer_position);
 
207
                        IFCALL(pointer->PointerPosition, context, &pointer->pointer_position);
 
208
                        break;
 
209
 
 
210
                case FASTPATH_UPDATETYPE_COLOR:
 
211
                        update_read_pointer_color(s, &pointer->pointer_color);
 
212
                        IFCALL(pointer->PointerColor, context, &pointer->pointer_color);
 
213
                        break;
 
214
 
 
215
                case FASTPATH_UPDATETYPE_CACHED:
 
216
                        update_read_pointer_cached(s, &pointer->pointer_cached);
 
217
                        IFCALL(pointer->PointerCached, context, &pointer->pointer_cached);
 
218
                        break;
 
219
 
 
220
                case FASTPATH_UPDATETYPE_POINTER:
 
221
                        update_read_pointer_new(s, &pointer->pointer_new);
 
222
                        IFCALL(pointer->PointerNew, context, &pointer->pointer_new);
 
223
                        break;
 
224
 
 
225
                default:
 
226
                        DEBUG_WARN("unknown updateCode 0x%X", updateCode);
 
227
                        break;
 
228
        }
 
229
}
 
230
 
 
231
static void fastpath_recv_update_data(rdpFastPath* fastpath, STREAM* s)
 
232
{
 
233
        uint16 size;
 
234
        int next_pos;
 
235
        uint32 totalSize;
 
236
        uint8 updateCode;
 
237
        uint8 fragmentation;
 
238
        uint8 compression;
 
239
        uint8 compressionFlags;
 
240
        STREAM* update_stream;
 
241
        STREAM* comp_stream;
 
242
        rdpRdp  *rdp;
 
243
        uint32 roff;
 
244
        uint32 rlen;
 
245
 
 
246
        rdp = fastpath->rdp;
 
247
 
 
248
        fastpath_read_update_header(s, &updateCode, &fragmentation, &compression);
 
249
 
 
250
        if (compression == FASTPATH_OUTPUT_COMPRESSION_USED)
 
251
                stream_read_uint8(s, compressionFlags);
 
252
        else
 
253
                compressionFlags = 0;
 
254
 
 
255
        stream_read_uint16(s, size);
 
256
        next_pos = stream_get_pos(s) + size;
 
257
        comp_stream = s;
 
258
 
 
259
        if (compressionFlags & PACKET_COMPRESSED)
 
260
        {
 
261
                if (decompress_rdp(rdp, s->p, size, compressionFlags, &roff, &rlen))
 
262
                {
 
263
                        comp_stream = stream_new(0);
 
264
                        comp_stream->data = rdp->mppc->history_buf + roff;
 
265
                        comp_stream->p = comp_stream->data;
 
266
                        comp_stream->size = rlen;
 
267
                        size = comp_stream->size;
 
268
                }
 
269
                else
 
270
                {
 
271
                        printf("decompress_rdp() failed\n");
 
272
                        stream_seek(s, size);
 
273
                }
 
274
        }
 
275
 
 
276
        update_stream = NULL;
 
277
        if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
 
278
        {
 
279
                totalSize = size;
 
280
                update_stream = comp_stream;
 
281
        }
 
282
        else
 
283
        {
 
284
                if (fragmentation == FASTPATH_FRAGMENT_FIRST)
 
285
                        stream_set_pos(fastpath->updateData, 0);
 
286
 
 
287
                stream_check_size(fastpath->updateData, size);
 
288
                stream_copy(fastpath->updateData, comp_stream, size);
 
289
 
 
290
                if (fragmentation == FASTPATH_FRAGMENT_LAST)
 
291
                {
 
292
                        update_stream = fastpath->updateData;
 
293
                        totalSize = stream_get_length(update_stream);
 
294
                        stream_set_pos(update_stream, 0);
 
295
                }
 
296
        }
 
297
 
 
298
        if (update_stream)
 
299
                fastpath_recv_update(fastpath, updateCode, totalSize, update_stream);
 
300
 
 
301
        stream_set_pos(s, next_pos);
 
302
 
 
303
        if (comp_stream != s)
 
304
                xfree(comp_stream);
 
305
}
 
306
 
 
307
boolean fastpath_recv_updates(rdpFastPath* fastpath, STREAM* s)
 
308
{
 
309
        rdpUpdate* update = fastpath->rdp->update;
 
310
 
 
311
        IFCALL(update->BeginPaint, update->context);
 
312
 
 
313
        while (stream_get_left(s) >= 3)
 
314
        {
 
315
                fastpath_recv_update_data(fastpath, s);
 
316
        }
 
317
 
 
318
        IFCALL(update->EndPaint, update->context);
 
319
 
 
320
        return true;
 
321
}
 
322
 
 
323
static boolean fastpath_read_input_event_header(STREAM* s, uint8* eventFlags, uint8* eventCode)
 
324
{
 
325
        uint8 eventHeader;
 
326
 
 
327
        if (stream_get_left(s) < 1)
 
328
                return false;
 
329
 
 
330
        stream_read_uint8(s, eventHeader); /* eventHeader (1 byte) */
 
331
 
 
332
        *eventFlags = (eventHeader & 0x1F);
 
333
        *eventCode = (eventHeader >> 5);
 
334
 
 
335
        return true;
 
336
}
 
337
 
 
338
static boolean fastpath_recv_input_event_scancode(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags)
 
339
{
 
340
        uint16 flags;
 
341
        uint16 code;
 
342
 
 
343
        if (stream_get_left(s) < 1)
 
344
                return false;
 
345
 
 
346
        stream_read_uint8(s, code); /* keyCode (1 byte) */
 
347
 
 
348
        flags = 0;
 
349
        if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
 
350
                flags |= KBD_FLAGS_RELEASE;
 
351
        else
 
352
                flags |= KBD_FLAGS_DOWN;
 
353
 
 
354
        if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_EXTENDED))
 
355
                flags |= KBD_FLAGS_EXTENDED;
 
356
 
 
357
        IFCALL(fastpath->rdp->input->KeyboardEvent, fastpath->rdp->input, flags, code);
 
358
 
 
359
        return true;
 
360
}
 
361
 
 
362
static boolean fastpath_recv_input_event_mouse(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags)
 
363
{
 
364
        uint16 pointerFlags;
 
365
        uint16 xPos;
 
366
        uint16 yPos;
 
367
 
 
368
        if (stream_get_left(s) < 6)
 
369
                return false;
 
370
 
 
371
        stream_read_uint16(s, pointerFlags); /* pointerFlags (2 bytes) */
 
372
        stream_read_uint16(s, xPos); /* xPos (2 bytes) */
 
373
        stream_read_uint16(s, yPos); /* yPos (2 bytes) */
 
374
 
 
375
        IFCALL(fastpath->rdp->input->MouseEvent, fastpath->rdp->input, pointerFlags, xPos, yPos);
 
376
 
 
377
        return true;
 
378
}
 
379
 
 
380
static boolean fastpath_recv_input_event_mousex(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags)
 
381
{
 
382
        uint16 pointerFlags;
 
383
        uint16 xPos;
 
384
        uint16 yPos;
 
385
 
 
386
        if (stream_get_left(s) < 6)
 
387
                return false;
 
388
 
 
389
        stream_read_uint16(s, pointerFlags); /* pointerFlags (2 bytes) */
 
390
        stream_read_uint16(s, xPos); /* xPos (2 bytes) */
 
391
        stream_read_uint16(s, yPos); /* yPos (2 bytes) */
 
392
 
 
393
        IFCALL(fastpath->rdp->input->ExtendedMouseEvent, fastpath->rdp->input, pointerFlags, xPos, yPos);
 
394
 
 
395
        return true;
 
396
}
 
397
 
 
398
static boolean fastpath_recv_input_event_sync(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags)
 
399
{
 
400
        IFCALL(fastpath->rdp->input->SynchronizeEvent, fastpath->rdp->input, eventFlags);
 
401
 
 
402
        return true;
 
403
}
 
404
 
 
405
static boolean fastpath_recv_input_event_unicode(rdpFastPath* fastpath, STREAM* s, uint8 eventFlags)
 
406
{
 
407
        uint16 unicodeCode;
 
408
 
 
409
        if (stream_get_left(s) < 2)
 
410
                return false;
 
411
 
 
412
        stream_read_uint16(s, unicodeCode); /* unicodeCode (2 bytes) */
 
413
 
 
414
        IFCALL(fastpath->rdp->input->UnicodeKeyboardEvent, fastpath->rdp->input, unicodeCode);
 
415
 
 
416
        return true;
 
417
}
 
418
 
 
419
static boolean fastpath_recv_input_event(rdpFastPath* fastpath, STREAM* s)
 
420
{
 
421
        uint8 eventFlags;
 
422
        uint8 eventCode;
 
423
 
 
424
        if (!fastpath_read_input_event_header(s, &eventFlags, &eventCode))
 
425
                return false;
 
426
 
 
427
        switch (eventCode)
 
428
        {
 
429
                case FASTPATH_INPUT_EVENT_SCANCODE:
 
430
                        if (!fastpath_recv_input_event_scancode(fastpath, s, eventFlags))
 
431
                                return false;
 
432
                        break;
 
433
 
 
434
                case FASTPATH_INPUT_EVENT_MOUSE:
 
435
                        if (!fastpath_recv_input_event_mouse(fastpath, s, eventFlags))
 
436
                                return false;
 
437
                        break;
 
438
 
 
439
                case FASTPATH_INPUT_EVENT_MOUSEX:
 
440
                        if (!fastpath_recv_input_event_mousex(fastpath, s, eventFlags))
 
441
                                return false;
 
442
                        break;
 
443
 
 
444
                case FASTPATH_INPUT_EVENT_SYNC:
 
445
                        if (!fastpath_recv_input_event_sync(fastpath, s, eventFlags))
 
446
                                return false;
 
447
                        break;
 
448
 
 
449
                case FASTPATH_INPUT_EVENT_UNICODE:
 
450
                        if (!fastpath_recv_input_event_unicode(fastpath, s, eventFlags))
 
451
                                return false;
 
452
                        break;
 
453
 
 
454
                default:
 
455
                        printf("Unknown eventCode %d\n", eventCode);
 
456
                        break;
 
457
        }
 
458
 
 
459
        return true;
 
460
}
 
461
 
 
462
boolean fastpath_recv_inputs(rdpFastPath* fastpath, STREAM* s)
 
463
{
 
464
        uint8 i;
 
465
 
 
466
        if (fastpath->numberEvents == 0)
 
467
        {
 
468
                /**
 
469
                 * If numberEvents is not provided in fpInputHeader, it will be provided
 
470
                 * as one additional byte here.
 
471
                 */
 
472
 
 
473
                if (stream_get_left(s) < 1)
 
474
                        return false;
 
475
 
 
476
                stream_read_uint8(s, fastpath->numberEvents); /* eventHeader (1 byte) */
 
477
        }
 
478
 
 
479
        for (i = 0; i < fastpath->numberEvents; i++)
 
480
        {
 
481
                if (!fastpath_recv_input_event(fastpath, s))
 
482
                        return false;
 
483
        }
 
484
 
 
485
        return true;
 
486
}
 
487
 
 
488
STREAM* fastpath_input_pdu_init(rdpFastPath* fastpath, uint8 eventFlags, uint8 eventCode)
 
489
{
 
490
        STREAM* s;
 
491
        s = transport_send_stream_init(fastpath->rdp->transport, 127);
 
492
        stream_seek(s, 2); /* fpInputHeader and length1 */
 
493
        /* length2 is not necessary since input PDU should not exceed 127 bytes */
 
494
        stream_write_uint8(s, eventFlags | (eventCode << 5)); /* eventHeader (1 byte) */
 
495
        return s;
 
496
}
 
497
 
 
498
boolean fastpath_send_input_pdu(rdpFastPath* fastpath, STREAM* s)
 
499
{
 
500
        uint16 length;
 
501
 
 
502
        length = stream_get_length(s);
 
503
        if (length > 127)
 
504
        {
 
505
                printf("Maximum FastPath PDU length is 127\n");
 
506
                return false;
 
507
        }
 
508
 
 
509
        stream_set_pos(s, 0);
 
510
        stream_write_uint8(s, (1 << 2));
 
511
        stream_write_uint8(s, length);
 
512
 
 
513
        stream_set_pos(s, length);
 
514
        if (transport_write(fastpath->rdp->transport, s) < 0)
 
515
                return false;
 
516
 
 
517
        return true;
 
518
}
 
519
 
 
520
STREAM* fastpath_update_pdu_init(rdpFastPath* fastpath)
 
521
{
 
522
        STREAM* s;
 
523
        s = transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE);
 
524
        stream_seek(s, 3); /* fpOutputHeader, length1 and length2 */
 
525
        stream_seek(s, 3); /* updateHeader, size */
 
526
        return s;
 
527
}
 
528
 
 
529
boolean fastpath_send_update_pdu(rdpFastPath* fastpath, uint8 updateCode, STREAM* s)
 
530
{
 
531
        uint8* bm;
 
532
        int fragment;
 
533
        uint16 length;
 
534
        boolean result;
 
535
        uint16 pduLength;
 
536
        uint16 maxLength;
 
537
        uint32 totalLength;
 
538
        uint8 fragmentation;
 
539
        STREAM* update;
 
540
 
 
541
        result = true;
 
542
 
 
543
        maxLength = FASTPATH_MAX_PACKET_SIZE - 6;
 
544
        totalLength = stream_get_length(s) - 6;
 
545
        stream_set_pos(s, 0);
 
546
        update = stream_new(0);
 
547
 
 
548
        for (fragment = 0; totalLength > 0; fragment++)
 
549
        {
 
550
                length = MIN(maxLength, totalLength);
 
551
                totalLength -= length;
 
552
                pduLength = length + 6;
 
553
 
 
554
                if (totalLength == 0)
 
555
                        fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST;
 
556
                else
 
557
                        fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT;
 
558
 
 
559
                stream_get_mark(s, bm);
 
560
                stream_write_uint8(s, 0); /* fpOutputHeader (1 byte) */
 
561
                stream_write_uint8(s, 0x80 | (pduLength >> 8)); /* length1 */
 
562
                stream_write_uint8(s, pduLength & 0xFF); /* length2 */
 
563
                fastpath_write_update_header(s, updateCode, fragmentation, 0);
 
564
                stream_write_uint16(s, length);
 
565
 
 
566
                stream_attach(update, bm, pduLength);
 
567
                stream_seek(update, pduLength);
 
568
                if (transport_write(fastpath->rdp->transport, update) < 0)
 
569
                {
 
570
                        stream_detach(update);
 
571
                        result = false;
 
572
                        break;
 
573
                }
 
574
                stream_detach(update);
 
575
 
 
576
                /* Reserve 6 bytes for the next fragment header, if any. */
 
577
                stream_seek(s, length - 6);
 
578
        }
 
579
 
 
580
        stream_free(update);
 
581
 
 
582
        return result;
 
583
}
 
584
 
 
585
rdpFastPath* fastpath_new(rdpRdp* rdp)
 
586
{
 
587
        rdpFastPath* fastpath;
 
588
 
 
589
        fastpath = xnew(rdpFastPath);
 
590
        fastpath->rdp = rdp;
 
591
        fastpath->updateData = stream_new(4096);
 
592
 
 
593
        return fastpath;
 
594
}
 
595
 
 
596
void fastpath_free(rdpFastPath* fastpath)
 
597
{
 
598
        stream_free(fastpath->updateData);
 
599
        xfree(fastpath);
 
600
}