a02e8d9f107f0fbd784b02d16c6e54c0402fa9d8
[platform/upstream/freerdp.git] / libfreerdp / core / fastpath.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include <winpr/crt.h>
29 #include <winpr/stream.h>
30
31 #include <freerdp/api.h>
32 #include <freerdp/crypto/per.h>
33
34 #include "orders.h"
35 #include "update.h"
36 #include "surface.h"
37 #include "fastpath.h"
38 #include "rdp.h"
39
40 /**
41  * Fast-Path packet format is defined in [MS-RDPBCGR] 2.2.9.1.2, which revises
42  * server output packets from the first byte with the goal of improving
43  * bandwidth.
44  * 
45  * Slow-Path packet always starts with TPKT header, which has the first
46  * byte 0x03, while Fast-Path packet starts with 2 zero bits in the first
47  * two less significant bits of the first byte.
48  */
49
50 #define FASTPATH_MAX_PACKET_SIZE 0x3FFF
51
52 #ifdef WITH_DEBUG_RDP
53 static const char* const FASTPATH_UPDATETYPE_STRINGS[] =
54 {
55         "Orders",                                                                       /* 0x0 */
56         "Bitmap",                                                                       /* 0x1 */
57         "Palette",                                                              /* 0x2 */
58         "Synchronize",                                          /* 0x3 */
59         "Surface Commands",                             /* 0x4 */
60         "System Pointer Hidden",        /* 0x5 */
61         "System Pointer Default",       /* 0x6 */
62         "???",                                                                          /* 0x7 */
63         "Pointer Position",                             /* 0x8 */
64         "Color Pointer",                                        /* 0x9 */
65         "Cached Pointer",                                       /* 0xA */
66         "New Pointer",                                          /* 0xB */
67 };
68 #endif
69
70 /*
71  * The fastpath header may be two or three bytes long.
72  * This function assumes that at least two bytes are available in the stream
73  * and doesn't touch third byte.
74  */
75 UINT16 fastpath_header_length(wStream* s)
76 {
77         BYTE length1;
78
79         Stream_Seek_BYTE(s);
80         stream_read_BYTE(s, length1);
81         Stream_Rewind(s, 2);
82
83         return ((length1 & 0x80) != 0 ? 3 : 2);
84 }
85
86 /**
87  * Read a Fast-Path packet header.\n
88  * @param s stream
89  * @param encryptionFlags
90  * @return length
91  */
92 UINT16 fastpath_read_header(rdpFastPath* fastpath, wStream* s)
93 {
94         BYTE header;
95         UINT16 length;
96
97         stream_read_BYTE(s, header);
98
99         if (fastpath)
100         {
101                 fastpath->encryptionFlags = (header & 0xC0) >> 6;
102                 fastpath->numberEvents = (header & 0x3C) >> 2;
103         }
104
105         per_read_length(s, &length);
106
107         return length;
108 }
109
110 static INLINE void fastpath_read_update_header(wStream* s, BYTE* updateCode, BYTE* fragmentation, BYTE* compression)
111 {
112         BYTE updateHeader;
113
114         stream_read_BYTE(s, updateHeader);
115         *updateCode = updateHeader & 0x0F;
116         *fragmentation = (updateHeader >> 4) & 0x03;
117         *compression = (updateHeader >> 6) & 0x03;
118 }
119
120 static INLINE void fastpath_write_update_header(wStream* s, BYTE updateCode, BYTE fragmentation, BYTE compression)
121 {
122         BYTE updateHeader = 0;
123
124         updateHeader |= updateCode & 0x0F;
125         updateHeader |= (fragmentation & 0x03) << 4;
126         updateHeader |= (compression & 0x03) << 6;
127         stream_write_BYTE(s, updateHeader);
128 }
129
130 BOOL fastpath_read_header_rdp(rdpFastPath* fastpath, wStream* s, UINT16 *length)
131 {
132         BYTE header;
133
134         stream_read_BYTE(s, header);
135
136         if (fastpath)
137         {
138                 fastpath->encryptionFlags = (header & 0xC0) >> 6;
139                 fastpath->numberEvents = (header & 0x3C) >> 2;
140         }
141
142         if (!per_read_length(s, length))
143                 return FALSE;
144
145         *length = *length - Stream_GetPosition(s);
146         return TRUE;
147 }
148
149 static BOOL fastpath_recv_orders(rdpFastPath* fastpath, wStream* s)
150 {
151         rdpUpdate* update = fastpath->rdp->update;
152         UINT16 numberOrders;
153
154         stream_read_UINT16(s, numberOrders); /* numberOrders (2 bytes) */
155
156         while (numberOrders > 0)
157         {
158                 if (!update_recv_order(update, s))
159                         return FALSE;
160
161                 numberOrders--;
162         }
163
164         return TRUE;
165 }
166
167 static BOOL fastpath_recv_update_common(rdpFastPath* fastpath, wStream* s)
168 {
169         UINT16 updateType;
170         rdpUpdate* update = fastpath->rdp->update;
171         rdpContext* context = update->context;
172
173         if (Stream_GetRemainingLength(s) < 2)
174                 return FALSE;
175
176         stream_read_UINT16(s, updateType); /* updateType (2 bytes) */
177
178         switch (updateType)
179         {
180                 case UPDATE_TYPE_BITMAP:
181                         if (!update_read_bitmap(update, s, &update->bitmap_update))
182                                 return FALSE;
183                         IFCALL(update->BitmapUpdate, context, &update->bitmap_update);
184                         break;
185
186                 case UPDATE_TYPE_PALETTE:
187                         if (!update_read_palette(update, s, &update->palette_update))
188                                 return FALSE;
189                         IFCALL(update->Palette, context, &update->palette_update);
190                         break;
191         }
192         return TRUE;
193 }
194
195 static BOOL fastpath_recv_update_synchronize(rdpFastPath* fastpath, wStream* s)
196 {
197         /* server 2008 can send invalid synchronize packet with missing padding,
198           so don't return FALSE even if the packet is invalid */
199         stream_skip(s, 2); /* size (2 bytes), MUST be set to zero */
200         return TRUE;
201 }
202
203 static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 size, wStream* s)
204 {
205         int status = 0;
206         rdpUpdate* update = fastpath->rdp->update;
207         rdpContext* context = fastpath->rdp->update->context;
208         rdpPointerUpdate* pointer = update->pointer;
209
210 #ifdef WITH_DEBUG_RDP
211         DEBUG_RDP("recv Fast-Path %s Update (0x%X), length:%d",
212                 updateCode < ARRAYSIZE(FASTPATH_UPDATETYPE_STRINGS) ? FASTPATH_UPDATETYPE_STRINGS[updateCode] : "???", updateCode, capacity);
213 #endif
214
215         switch (updateCode)
216         {
217                 case FASTPATH_UPDATETYPE_ORDERS:
218                         if (!fastpath_recv_orders(fastpath, s))
219                                 return -1;
220                         break;
221
222                 case FASTPATH_UPDATETYPE_BITMAP:
223                 case FASTPATH_UPDATETYPE_PALETTE:
224                         if (!fastpath_recv_update_common(fastpath, s))
225                                 return -1;
226                         break;
227
228                 case FASTPATH_UPDATETYPE_SYNCHRONIZE:
229                         if (!fastpath_recv_update_synchronize(fastpath, s))
230                                 fprintf(stderr, "fastpath_recv_update_synchronize failure but we continue\n");
231                         else
232                                 IFCALL(update->Synchronize, context);                   
233                         break;
234
235                 case FASTPATH_UPDATETYPE_SURFCMDS:
236                         status = update_recv_surfcmds(update, size, s);
237                         break;
238
239                 case FASTPATH_UPDATETYPE_PTR_NULL:
240                         pointer->pointer_system.type = SYSPTR_NULL;
241                         IFCALL(pointer->PointerSystem, context, &pointer->pointer_system);
242                         break;
243
244                 case FASTPATH_UPDATETYPE_PTR_DEFAULT:
245                         update->pointer->pointer_system.type = SYSPTR_DEFAULT;
246                         IFCALL(pointer->PointerSystem, context, &pointer->pointer_system);
247
248                         break;
249
250                 case FASTPATH_UPDATETYPE_PTR_POSITION:
251                         if (!update_read_pointer_position(s, &pointer->pointer_position))
252                                 return -1;
253                         IFCALL(pointer->PointerPosition, context, &pointer->pointer_position);
254                         break;
255
256                 case FASTPATH_UPDATETYPE_COLOR:
257                         if (!update_read_pointer_color(s, &pointer->pointer_color))
258                                 return -1;
259                         IFCALL(pointer->PointerColor, context, &pointer->pointer_color);
260                         break;
261
262                 case FASTPATH_UPDATETYPE_CACHED:
263                         if (!update_read_pointer_cached(s, &pointer->pointer_cached))
264                                 return -1;
265                         IFCALL(pointer->PointerCached, context, &pointer->pointer_cached);
266                         break;
267
268                 case FASTPATH_UPDATETYPE_POINTER:
269                         if (!update_read_pointer_new(s, &pointer->pointer_new))
270                                 return -1;
271                         IFCALL(pointer->PointerNew, context, &pointer->pointer_new);
272                         break;
273
274                 default:
275                         DEBUG_WARN("unknown updateCode 0x%X", updateCode);
276                         break;
277         }
278
279         return status;
280 }
281
282 const char* fastpath_get_fragmentation_string(BYTE fragmentation)
283 {
284         if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
285                 return "FASTPATH_FRAGMENT_SINGLE";
286         else if (fragmentation == FASTPATH_FRAGMENT_LAST)
287                 return "FASTPATH_FRAGMENT_LAST";
288         else if (fragmentation == FASTPATH_FRAGMENT_FIRST)
289                 return "FASTPATH_FRAGMENT_FIRST";
290         else if (fragmentation == FASTPATH_FRAGMENT_NEXT)
291                 return "FASTPATH_FRAGMENT_NEXT";
292
293         return "FASTPATH_FRAGMENT_UNKNOWN";
294 }
295
296 static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
297 {
298         int status;
299         UINT16 size;
300         UINT32 roff;
301         UINT32 rlen;
302         rdpRdp* rdp;
303         int next_pos;
304         BYTE* buffer;
305         wStream* cs;
306         UINT32 totalSize;
307         BYTE updateCode;
308         BYTE fragmentation;
309         BYTE compression;
310         BYTE compressionFlags;
311         rdpTransport* transport;
312
313         status = 0;
314         rdp = fastpath->rdp;
315         transport = fastpath->rdp->transport;
316
317         fastpath_read_update_header(s, &updateCode, &fragmentation, &compression);
318
319         if (compression == FASTPATH_OUTPUT_COMPRESSION_USED)
320                 stream_read_BYTE(s, compressionFlags);
321         else
322                 compressionFlags = 0;
323
324         stream_read_UINT16(s, size);
325
326         if (Stream_GetRemainingLength(s) < size)
327                 return -1;
328
329         cs = s;
330         next_pos = Stream_GetPosition(s) + size;
331
332         if (compressionFlags & PACKET_COMPRESSED)
333         {
334                 if (decompress_rdp(rdp->mppc_dec, s->pointer, size, compressionFlags, &roff, &rlen))
335                 {
336                         size = rlen;
337                         buffer = rdp->mppc_dec->history_buf + roff;
338
339                         cs = StreamPool_Take(transport->ReceivePool, size);
340
341                         Stream_SetPosition(cs, 0);
342                         Stream_Write(cs, buffer, size);
343                         Stream_SealLength(cs);
344                         Stream_SetPosition(cs, 0);
345                 }
346                 else
347                 {
348                         fprintf(stderr, "decompress_rdp() failed\n");
349                         Stream_Seek(s, size);
350                 }
351         }
352
353         if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
354         {
355                 if (fastpath->fragmentation != -1)
356                 {
357                         fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_SINGLE\n");
358                         return -1;
359                 }
360
361                 totalSize = size;
362                 status = fastpath_recv_update(fastpath, updateCode, totalSize, cs);
363
364                 if (status < 0)
365                         return -1;
366         }
367         else
368         {
369                 if (fragmentation == FASTPATH_FRAGMENT_FIRST)
370                 {
371                         if (fastpath->fragmentation != -1)
372                         {
373                                 fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_FIRST\n");
374                                 return -1;
375                         }
376
377                         fastpath->fragmentation = FASTPATH_FRAGMENT_FIRST;
378
379                         totalSize = size;
380
381                         if (totalSize > transport->settings->MultifragMaxRequestSize)
382                         {
383                                 fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n",
384                                                 totalSize, transport->settings->MultifragMaxRequestSize);
385                                 return -1;
386                         }
387
388                         fastpath->updateData = StreamPool_Take(transport->ReceivePool, size);
389                         Stream_SetPosition(fastpath->updateData, 0);
390
391                         Stream_Copy(fastpath->updateData, cs, size);
392                 }
393                 else if (fragmentation == FASTPATH_FRAGMENT_NEXT)
394                 {
395                         if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) &&
396                                         (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT))
397                         {
398                                 fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_NEXT\n");
399                                 return -1;
400                         }
401
402                         fastpath->fragmentation = FASTPATH_FRAGMENT_NEXT;
403
404                         totalSize = Stream_GetPosition(fastpath->updateData) + size;
405
406                         if (totalSize > transport->settings->MultifragMaxRequestSize)
407                         {
408                                 fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n",
409                                                 totalSize, transport->settings->MultifragMaxRequestSize);
410                                 return -1;
411                         }
412
413                         Stream_EnsureCapacity(fastpath->updateData, totalSize);
414
415                         Stream_Copy(fastpath->updateData, cs, size);
416                 }
417                 else if (fragmentation == FASTPATH_FRAGMENT_LAST)
418                 {
419                         if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) &&
420                                         (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT))
421                         {
422                                 fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_LAST\n");
423                                 return -1;
424                         }
425
426                         fastpath->fragmentation = -1;
427
428                         totalSize = Stream_GetPosition(fastpath->updateData) + size;
429
430                         if (totalSize > transport->settings->MultifragMaxRequestSize)
431                         {
432                                 fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n",
433                                                 totalSize, transport->settings->MultifragMaxRequestSize);
434                                 return -1;
435                         }
436
437                         Stream_EnsureCapacity(fastpath->updateData, totalSize);
438
439                         Stream_Copy(fastpath->updateData, cs, size);
440
441                         Stream_SealLength(fastpath->updateData);
442                         Stream_SetPosition(fastpath->updateData, 0);
443
444                         status = fastpath_recv_update(fastpath, updateCode, totalSize, fastpath->updateData);
445
446                         Stream_Release(fastpath->updateData);
447
448                         if (status < 0)
449                                 return -1;
450                 }
451         }
452
453         Stream_SetPosition(s, next_pos);
454
455         if (cs != s)
456                 Stream_Release(cs);
457
458         return status;
459 }
460
461 int fastpath_recv_updates(rdpFastPath* fastpath, wStream* s)
462 {
463         int status = 0;
464         rdpUpdate* update = fastpath->rdp->update;
465
466         IFCALL(update->BeginPaint, update->context);
467
468         while (Stream_GetRemainingLength(s) >= 3)
469         {
470                 if (fastpath_recv_update_data(fastpath, s) < 0)
471                         return -1;
472         }
473
474         IFCALL(update->EndPaint, update->context);
475
476         return status;
477 }
478
479 static BOOL fastpath_read_input_event_header(wStream* s, BYTE* eventFlags, BYTE* eventCode)
480 {
481         BYTE eventHeader;
482
483         if (Stream_GetRemainingLength(s) < 1)
484                 return FALSE;
485
486         stream_read_BYTE(s, eventHeader); /* eventHeader (1 byte) */
487
488         *eventFlags = (eventHeader & 0x1F);
489         *eventCode = (eventHeader >> 5);
490
491         return TRUE;
492 }
493
494 static BOOL fastpath_recv_input_event_scancode(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
495 {
496         UINT16 flags;
497         UINT16 code;
498
499         if (Stream_GetRemainingLength(s) < 1)
500                 return FALSE;
501
502         stream_read_BYTE(s, code); /* keyCode (1 byte) */
503
504         flags = 0;
505
506         if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
507                 flags |= KBD_FLAGS_RELEASE;
508         else
509                 flags |= KBD_FLAGS_DOWN;
510
511         if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_EXTENDED))
512                 flags |= KBD_FLAGS_EXTENDED;
513
514         IFCALL(fastpath->rdp->input->KeyboardEvent, fastpath->rdp->input, flags, code);
515
516         return TRUE;
517 }
518
519 static BOOL fastpath_recv_input_event_mouse(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
520 {
521         UINT16 pointerFlags;
522         UINT16 xPos;
523         UINT16 yPos;
524
525         if (Stream_GetRemainingLength(s) < 6)
526                 return FALSE;
527
528         stream_read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
529         stream_read_UINT16(s, xPos); /* xPos (2 bytes) */
530         stream_read_UINT16(s, yPos); /* yPos (2 bytes) */
531
532         IFCALL(fastpath->rdp->input->MouseEvent, fastpath->rdp->input, pointerFlags, xPos, yPos);
533
534         return TRUE;
535 }
536
537 static BOOL fastpath_recv_input_event_mousex(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
538 {
539         UINT16 pointerFlags;
540         UINT16 xPos;
541         UINT16 yPos;
542
543         if (Stream_GetRemainingLength(s) < 6)
544                 return FALSE;
545
546         stream_read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
547         stream_read_UINT16(s, xPos); /* xPos (2 bytes) */
548         stream_read_UINT16(s, yPos); /* yPos (2 bytes) */
549
550         IFCALL(fastpath->rdp->input->ExtendedMouseEvent, fastpath->rdp->input, pointerFlags, xPos, yPos);
551
552         return TRUE;
553 }
554
555 static BOOL fastpath_recv_input_event_sync(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
556 {
557         IFCALL(fastpath->rdp->input->SynchronizeEvent, fastpath->rdp->input, eventFlags);
558
559         return TRUE;
560 }
561
562 static BOOL fastpath_recv_input_event_unicode(rdpFastPath* fastpath, wStream* s, BYTE eventFlags)
563 {
564         UINT16 unicodeCode;
565         UINT16 flags;
566
567         if (Stream_GetRemainingLength(s) < 2)
568                 return FALSE;
569
570         stream_read_UINT16(s, unicodeCode); /* unicodeCode (2 bytes) */
571
572         flags = 0;
573
574         if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
575                 flags |= KBD_FLAGS_RELEASE;
576         else
577                 flags |= KBD_FLAGS_DOWN;
578
579         IFCALL(fastpath->rdp->input->UnicodeKeyboardEvent, fastpath->rdp->input, flags, unicodeCode);
580
581         return TRUE;
582 }
583
584 static BOOL fastpath_recv_input_event(rdpFastPath* fastpath, wStream* s)
585 {
586         BYTE eventFlags;
587         BYTE eventCode;
588
589         if (!fastpath_read_input_event_header(s, &eventFlags, &eventCode))
590                 return FALSE;
591
592         switch (eventCode)
593         {
594                 case FASTPATH_INPUT_EVENT_SCANCODE:
595                         if (!fastpath_recv_input_event_scancode(fastpath, s, eventFlags))
596                                 return FALSE;
597                         break;
598
599                 case FASTPATH_INPUT_EVENT_MOUSE:
600                         if (!fastpath_recv_input_event_mouse(fastpath, s, eventFlags))
601                                 return FALSE;
602                         break;
603
604                 case FASTPATH_INPUT_EVENT_MOUSEX:
605                         if (!fastpath_recv_input_event_mousex(fastpath, s, eventFlags))
606                                 return FALSE;
607                         break;
608
609                 case FASTPATH_INPUT_EVENT_SYNC:
610                         if (!fastpath_recv_input_event_sync(fastpath, s, eventFlags))
611                                 return FALSE;
612                         break;
613
614                 case FASTPATH_INPUT_EVENT_UNICODE:
615                         if (!fastpath_recv_input_event_unicode(fastpath, s, eventFlags))
616                                 return FALSE;
617                         break;
618
619                 default:
620                         fprintf(stderr, "Unknown eventCode %d\n", eventCode);
621                         break;
622         }
623
624         return TRUE;
625 }
626
627 int fastpath_recv_inputs(rdpFastPath* fastpath, wStream* s)
628 {
629         BYTE i;
630
631         if (fastpath->numberEvents == 0)
632         {
633                 /**
634                  * If numberEvents is not provided in fpInputHeader, it will be provided
635                  * as one additional byte here.
636                  */
637
638                 if (Stream_GetRemainingLength(s) < 1)
639                         return -1;
640
641                 stream_read_BYTE(s, fastpath->numberEvents); /* eventHeader (1 byte) */
642         }
643
644         for (i = 0; i < fastpath->numberEvents; i++)
645         {
646                 if (!fastpath_recv_input_event(fastpath, s))
647                         return -1;
648         }
649
650         return 0;
651 }
652
653 static UINT32 fastpath_get_sec_bytes(rdpRdp* rdp)
654 {
655         UINT32 sec_bytes;
656
657         sec_bytes = 0;
658
659         if (rdp->do_crypt)
660         {
661                 sec_bytes = 8;
662
663                 if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
664                         sec_bytes += 4;
665         }
666
667         return sec_bytes;
668 }
669
670 wStream* fastpath_input_pdu_init_header(rdpFastPath* fastpath)
671 {
672         rdpRdp *rdp;
673         wStream* s;
674
675         rdp = fastpath->rdp;
676
677         s = transport_send_stream_init(rdp->transport, 256);
678
679         Stream_Seek(s, 3); /* fpInputHeader, length1 and length2 */
680
681         if (rdp->do_crypt)
682         {
683                 rdp->sec_flags |= SEC_ENCRYPT;
684
685                 if (rdp->do_secure_checksum)
686                         rdp->sec_flags |= SEC_SECURE_CHECKSUM;
687         }
688
689         Stream_Seek(s, fastpath_get_sec_bytes(rdp));
690
691         return s;
692 }
693
694 wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE eventCode)
695 {
696         rdpRdp *rdp;
697         wStream* s;
698
699         rdp = fastpath->rdp;
700
701         s = fastpath_input_pdu_init_header(fastpath);
702         stream_write_BYTE(s, eventFlags | (eventCode << 5)); /* eventHeader (1 byte) */
703
704         return s;
705 }
706
707 BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNumEvents)
708 {
709         rdpRdp *rdp;
710         UINT16 length;
711         BYTE eventHeader;
712         int sec_bytes;
713
714         rdp = fastpath->rdp;
715
716         length = Stream_GetPosition(s);
717
718         if (length >= (2 << 14))
719         {
720                 fprintf(stderr, "Maximum FastPath PDU length is 32767\n");
721                 return FALSE;
722         }
723
724         eventHeader = FASTPATH_INPUT_ACTION_FASTPATH;
725 <<<<<<< HEAD
726         eventHeader |= (1 << 2); /* numberEvents */
727
728 =======
729         eventHeader |= (iNumEvents << 2); /* numberEvents */
730 >>>>>>> f1672948ff0b5f6a9d3cda658a18104df3c3d1e4
731         if (rdp->sec_flags & SEC_ENCRYPT)
732                 eventHeader |= (FASTPATH_INPUT_ENCRYPTED << 6);
733         if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
734                 eventHeader |= (FASTPATH_INPUT_SECURE_CHECKSUM << 6);
735
736         Stream_SetPosition(s, 0);
737         stream_write_BYTE(s, eventHeader);
738         sec_bytes = fastpath_get_sec_bytes(fastpath->rdp);
739
740         /*
741          * We always encode length in two bytes, even though we could use
742          * only one byte if length <= 0x7F. It is just easier that way,
743          * because we can leave room for fixed-length header, store all
744          * the data first and then store the header.
745          */
746         stream_write_UINT16_be(s, 0x8000 | length);
747
748         if (sec_bytes > 0)
749         {
750                 BYTE* fpInputEvents;
751                 UINT16 fpInputEvents_length;
752
753                 fpInputEvents = Stream_Pointer(s) + sec_bytes;
754                 fpInputEvents_length = length - 3 - sec_bytes;
755
756                 if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
757                         security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length, TRUE, Stream_Pointer(s));
758                 else
759                         security_mac_signature(rdp, fpInputEvents, fpInputEvents_length, Stream_Pointer(s));
760
761                 security_encrypt(fpInputEvents, fpInputEvents_length, rdp);
762         }
763
764         rdp->sec_flags = 0;
765
766         Stream_SetPosition(s, length);
767
768         if (transport_write(fastpath->rdp->transport, s) < 0)
769                 return FALSE;
770
771         return TRUE;
772 }
773
774 BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s)
775 {
776         return fastpath_send_multiple_input_pdu(fastpath, s, 1);
777 }
778
779 wStream* fastpath_update_pdu_init(rdpFastPath* fastpath)
780 {
781         wStream* s;
782
783         s = transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE);
784
785         Stream_Seek(s, 3); /* fpOutputHeader, length1 and length2 */
786         Stream_Seek(s, fastpath_get_sec_bytes(fastpath->rdp));
787         Stream_Seek(s, 3); /* updateHeader, size */
788
789         return s;
790 }
791
792 BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s)
793 {
794         rdpRdp* rdp;
795         BYTE* bm;
796         BYTE* ptr_to_crypt;
797         BYTE* ptr_sig;
798         BYTE* holdp;
799         int fragment;
800         int sec_bytes;
801         int try_comp;
802         int comp_flags;
803         int header_bytes;
804         int cflags;
805         int pdu_data_bytes;
806         int dlen;
807         int bytes_to_crypt;
808         BOOL result;
809         UINT16 pduLength;
810         UINT16 maxLength;
811         UINT32 totalLength;
812         BYTE fragmentation;
813         BYTE header;
814         wStream* update;
815         wStream* comp_update;
816         wStream* ls;
817
818         result = TRUE;
819         rdp = fastpath->rdp;
820         sec_bytes = fastpath_get_sec_bytes(rdp);
821         maxLength = FASTPATH_MAX_PACKET_SIZE - (6 + sec_bytes);
822         totalLength = Stream_GetPosition(s) - (6 + sec_bytes);
823         Stream_SetPosition(s, 0);
824         update = stream_new(0);
825         try_comp = rdp->settings->CompressionEnabled;
826         comp_update = stream_new(0);
827
828         for (fragment = 0; (totalLength > 0) || (fragment == 0); fragment++)
829         {
830                 stream_get_mark(s, holdp);
831                 ls = s;
832                 dlen = MIN(maxLength, totalLength);
833                 cflags = 0;
834                 comp_flags = 0;
835                 header_bytes = 6 + sec_bytes;
836                 pdu_data_bytes = dlen;
837
838                 if (try_comp)
839                 {
840                         if (compress_rdp(rdp->mppc_enc, ls->pointer + header_bytes, dlen))
841                         {
842                                 if (rdp->mppc_enc->flags & PACKET_COMPRESSED)
843                                 {
844                                         cflags = rdp->mppc_enc->flags;
845                                         pdu_data_bytes = rdp->mppc_enc->bytes_in_opb;
846                                         comp_flags = FASTPATH_OUTPUT_COMPRESSION_USED;
847                                         header_bytes = 7 + sec_bytes;
848                                         bm = (BYTE*) (rdp->mppc_enc->outputBuffer - header_bytes);
849                                         stream_attach(comp_update, bm, pdu_data_bytes + header_bytes);
850                                         ls = comp_update;
851                                 }
852                         }
853                         else
854                         {
855                                 fprintf(stderr, "fastpath_send_update_pdu: mppc_encode failed\n");
856                         }
857                 }
858
859                 totalLength -= dlen;
860                 pduLength = pdu_data_bytes + header_bytes;
861
862                 if (totalLength == 0)
863                         fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST;
864                 else
865                         fragmentation = (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT;
866
867                 stream_get_mark(ls, bm);
868                 header = 0;
869
870                 if (sec_bytes > 0)
871                         header |= (FASTPATH_OUTPUT_ENCRYPTED << 6);
872
873                 stream_write_BYTE(ls, header); /* fpOutputHeader (1 byte) */
874                 stream_write_BYTE(ls, 0x80 | (pduLength >> 8)); /* length1 */
875                 stream_write_BYTE(ls, pduLength & 0xFF); /* length2 */
876
877                 if (sec_bytes > 0)
878                         Stream_Seek(ls, sec_bytes);
879
880                 fastpath_write_update_header(ls, updateCode, fragmentation, comp_flags);
881
882                 /* extra byte if compressed */
883                 if (ls == comp_update)
884                 {
885                         stream_write_BYTE(ls, cflags);
886                         bytes_to_crypt = pdu_data_bytes + 4;
887                 }
888                 else
889                 {
890                         bytes_to_crypt = pdu_data_bytes + 3;
891                 }
892
893                 stream_write_UINT16(ls, pdu_data_bytes);
894
895                 stream_attach(update, bm, pduLength);
896                 Stream_Seek(update, pduLength);
897
898                 if (sec_bytes > 0)
899                 {
900                         /* does this work ? */
901                         ptr_to_crypt = bm + 3 + sec_bytes;
902                         ptr_sig = bm + 3;
903
904                         if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
905                                 security_salted_mac_signature(rdp, ptr_to_crypt, bytes_to_crypt, TRUE, ptr_sig);
906                         else
907                                 security_mac_signature(rdp, ptr_to_crypt, bytes_to_crypt, ptr_sig);
908
909                         security_encrypt(ptr_to_crypt, bytes_to_crypt, rdp);
910                 }
911
912                 if (transport_write(fastpath->rdp->transport, update) < 0)
913                 {
914                         result = FALSE;
915                         break;
916                 }
917
918                 /* Reserve 6 + sec_bytes bytes for the next fragment header, if any. */
919                 stream_set_mark(s, holdp + dlen);
920         }
921
922         stream_detach(update);
923         stream_detach(comp_update);
924         stream_free(update);
925         stream_free(comp_update);
926
927         return result;
928 }
929
930 rdpFastPath* fastpath_new(rdpRdp* rdp)
931 {
932         rdpFastPath* fastpath;
933
934         fastpath = (rdpFastPath*) malloc(sizeof(rdpFastPath));
935
936         if (fastpath)
937         {
938                 ZeroMemory(fastpath, sizeof(rdpFastPath));
939
940                 fastpath->rdp = rdp;
941                 fastpath->fragmentation = -1;
942         }
943
944         return fastpath;
945 }
946
947 void fastpath_free(rdpFastPath* fastpath)
948 {
949         if (fastpath)
950         {
951                 free(fastpath);
952         }
953 }