23#include <freerdp/config.h>
32#include <winpr/assert.h>
33#include <winpr/stream.h>
35#include <freerdp/api.h>
36#include <freerdp/log.h>
37#include <freerdp/crypto/per.h>
45#include "../cache/pointer.h"
46#include "../cache/palette.h"
47#include "../cache/bitmap.h"
49#define FTAG FREERDP_TAG("core.fastpath")
51enum FASTPATH_INPUT_ENCRYPTION_FLAGS
53 FASTPATH_INPUT_SECURE_CHECKSUM = 0x1,
54 FASTPATH_INPUT_ENCRYPTED = 0x2
57enum FASTPATH_OUTPUT_ENCRYPTION_FLAGS
59 FASTPATH_OUTPUT_SECURE_CHECKSUM = 0x1,
60 FASTPATH_OUTPUT_ENCRYPTED = 0x2
84static const char*
const FASTPATH_UPDATETYPE_STRINGS[] = {
90 "System Pointer Hidden",
91 "System Pointer Default",
100static const char* fastpath_update_to_string(UINT8 update)
102 if (update >= ARRAYSIZE(FASTPATH_UPDATETYPE_STRINGS))
105 return FASTPATH_UPDATETYPE_STRINGS[update];
109static BOOL fastpath_read_update_header(wLog* log,
wStream* s, BYTE* updateCode,
110 BYTE* fragmentation, BYTE* compression)
112 BYTE updateHeader = 0;
114 if (!s || !updateCode || !fragmentation || !compression)
117 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
120 Stream_Read_UINT8(s, updateHeader);
121 *updateCode = updateHeader & 0x0F;
122 *fragmentation = (updateHeader >> 4) & 0x03;
123 *compression = (updateHeader >> 6) & 0x03;
128static BOOL fastpath_write_update_header(wLog* log,
wStream* s,
131 BYTE updateHeader = 0;
132 WINPR_ASSERT(fpUpdateHeader);
134 updateHeader |= fpUpdateHeader->updateCode & 0x0F;
135 updateHeader |= (fpUpdateHeader->fragmentation & 0x03) << 4;
136 updateHeader |= (fpUpdateHeader->compression & 0x03) << 6;
138 if (!Stream_CheckAndLogRequiredCapacityWLog(log, s, 1))
140 Stream_Write_UINT8(s, updateHeader);
142 if (fpUpdateHeader->compression)
144 if (!Stream_CheckAndLogRequiredCapacityWLog(log, s, 1))
147 Stream_Write_UINT8(s, fpUpdateHeader->compressionFlags);
150 if (!Stream_CheckAndLogRequiredCapacityWLog(log, s, 2))
153 Stream_Write_UINT16(s, fpUpdateHeader->size);
160 WINPR_ASSERT(fpUpdateHeader);
161 return (fpUpdateHeader->compression) ? 4 : 3;
165static BOOL fastpath_write_update_pdu_header(wLog* log,
wStream* s,
169 BYTE fpOutputHeader = 0;
170 WINPR_ASSERT(fpUpdatePduHeader);
173 if (!Stream_CheckAndLogRequiredCapacityWLog(log, s, 3))
176 fpOutputHeader |= (fpUpdatePduHeader->action & 0x03);
177 fpOutputHeader |= (fpUpdatePduHeader->secFlags & 0x03) << 6;
178 Stream_Write_UINT8(s, fpOutputHeader);
179 Stream_Write_UINT8(s, 0x80 | (fpUpdatePduHeader->length >> 8));
180 Stream_Write_UINT8(s, fpUpdatePduHeader->length & 0xFF);
182 if (fpUpdatePduHeader->secFlags)
184 WINPR_ASSERT(rdp->settings);
186 ENCRYPTION_METHOD_FIPS)
188 if (!Stream_CheckAndLogRequiredCapacityWLog(log, s, 4))
191 Stream_Write(s, fpUpdatePduHeader->fipsInformation, 4);
194 if (!Stream_CheckAndLogRequiredCapacityWLog(log, s, 8))
197 Stream_Write(s, fpUpdatePduHeader->dataSignature, 8);
209 if (!fpUpdatePduHeader || !rdp)
212 if (fpUpdatePduHeader->secFlags)
216 WINPR_ASSERT(rdp->settings);
218 ENCRYPTION_METHOD_FIPS)
225BOOL fastpath_read_header_rdp(rdpFastPath* fastpath,
wStream* s, UINT16* length)
227 WINPR_ASSERT(fastpath);
229 WINPR_ASSERT(length);
231 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 1))
234 const BYTE header = Stream_Get_UINT8(s);
235 fastpath->encryptionFlags = (header & 0xC0) >> 6;
236 fastpath->numberEvents = (header & 0x3C) >> 2;
238 if (!per_read_length(s, length))
241 const size_t pos = Stream_GetPosition(s);
245 *length = *length - (UINT16)pos;
250static BOOL fastpath_recv_orders(rdpUpdate* update,
wStream* s)
252 UINT16 numberOrders = 0;
254 WINPR_ASSERT(update);
255 WINPR_ASSERT(update->context);
256 WINPR_ASSERT(update->context->rdp);
257 WINPR_ASSERT(update->context->rdp->fastpath);
259 wLog* log = update->context->rdp->fastpath->log;
262 WLog_Print(log, WLOG_ERROR,
"Invalid arguments");
268 WLog_Print(log, WLOG_ERROR,
"Invalid configuration");
272 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 2))
275 Stream_Read_UINT16(s, numberOrders);
277 while (numberOrders > 0)
279 if (!update_recv_order(update, s))
289static BOOL fastpath_recv_update_common(rdpUpdate* update,
wStream* s)
292 UINT16 updateType = 0;
293 BOOL defaultReturn = 0;
299 if (!update || !update->context)
302 rdpContext* context = update->context;
303 WINPR_ASSERT(context->rdp);
304 WINPR_ASSERT(context->rdp->fastpath);
308 if (!Stream_CheckAndLogRequiredLengthWLog(context->rdp->fastpath->log, s, 2))
311 Stream_Read_UINT16(s, updateType);
314 case UPDATE_TYPE_BITMAP:
316 BITMAP_UPDATE* bitmap_update = update_read_bitmap_update(update, s);
321 up->stats.base[RDP_STATS_BITMAP_UPDATE]++;
322 rc = IFCALLRESULT(defaultReturn, update->BitmapUpdate, context, bitmap_update);
323 free_bitmap_update(context, bitmap_update);
327 case UPDATE_TYPE_PALETTE:
334 up->stats.base[RDP_STATS_PALETTE]++;
335 rc = IFCALLRESULT(defaultReturn, update->Palette, context, palette_update);
336 free_palette_update(context, palette_update);
348static BOOL fastpath_recv_update_synchronize(WINPR_ATTR_UNUSED rdpFastPath* fastpath,
wStream* s)
352 WINPR_ASSERT(fastpath);
355 const size_t len = Stream_GetRemainingLength(s);
356 const size_t skip = MIN(2, len);
357 return Stream_SafeSeek(s, skip);
361static BOOL fastpath_recv_update_paint_block(rdpUpdate* update,
wStream* s,
362 BOOL (*fkt)(rdpUpdate*,
wStream*))
365 if (!update_begin_paint(update))
368 BOOL res = fkt(update, s);
369 if (!update_end_paint(update))
375static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode,
wStream* s)
380 if (!fastpath || !fastpath->rdp || !s)
383 Stream_SealLength(s);
384 Stream_ResetPosition(s);
386 rdpUpdate* update = fastpath->rdp->update;
388 if (!update || !update->pointer || !update->context)
393 rdpContext* context = update->context;
394 WINPR_ASSERT(context);
396 rdpPointerUpdate* pointer = update->pointer;
397 WINPR_ASSERT(pointer);
400 DEBUG_RDP(fastpath->rdp,
"recv Fast-Path %s Update (0x%02" PRIX8
"), length:%" PRIuz
"",
401 fastpath_update_to_string(updateCode), updateCode, Stream_GetRemainingLength(s));
404 const BOOL defaultReturn =
408 case FASTPATH_UPDATETYPE_ORDERS:
409 rc = fastpath_recv_update_paint_block(update, s, fastpath_recv_orders);
412 case FASTPATH_UPDATETYPE_BITMAP:
413 case FASTPATH_UPDATETYPE_PALETTE:
414 rc = fastpath_recv_update_paint_block(update, s, fastpath_recv_update_common);
417 case FASTPATH_UPDATETYPE_SYNCHRONIZE:
418 if (!fastpath_recv_update_synchronize(fastpath, s))
419 WLog_Print(fastpath->log, WLOG_ERROR,
420 "fastpath_recv_update_synchronize failure but we continue");
423 up->stats.base[RDP_STATS_SYNC]++;
424 rc = IFCALLRESULT(TRUE, update->Synchronize, context);
429 case FASTPATH_UPDATETYPE_SURFCMDS:
430 status = fastpath_recv_update_paint_block(update, s, update_recv_surfcmds);
434 case FASTPATH_UPDATETYPE_PTR_NULL:
437 pointer_system.type = SYSPTR_NULL;
438 up->stats.base[RDP_STATS_POINTER_SYSTEM]++;
439 rc = IFCALLRESULT(defaultReturn, pointer->PointerSystem, context, &pointer_system);
443 case FASTPATH_UPDATETYPE_PTR_DEFAULT:
446 pointer_system.type = SYSPTR_DEFAULT;
447 up->stats.base[RDP_STATS_POINTER_DEFAULT]++;
448 rc = IFCALLRESULT(defaultReturn, pointer->PointerSystem, context, &pointer_system);
452 case FASTPATH_UPDATETYPE_PTR_POSITION:
456 if (pointer_position)
458 up->stats.base[RDP_STATS_POINTER_POSITION]++;
459 rc = IFCALLRESULT(defaultReturn, pointer->PointerPosition, context,
461 free_pointer_position_update(context, pointer_position);
466 case FASTPATH_UPDATETYPE_COLOR:
472 up->stats.base[RDP_STATS_POINTER_COLOR]++;
473 rc = IFCALLRESULT(defaultReturn, pointer->PointerColor, context, pointer_color);
474 free_pointer_color_update(context, pointer_color);
479 case FASTPATH_UPDATETYPE_CACHED:
485 up->stats.base[RDP_STATS_POINTER_CACHED]++;
486 rc = IFCALLRESULT(defaultReturn, pointer->PointerCached, context, pointer_cached);
487 free_pointer_cached_update(context, pointer_cached);
492 case FASTPATH_UPDATETYPE_POINTER:
498 up->stats.base[RDP_STATS_POINTER_NEW]++;
499 rc = IFCALLRESULT(defaultReturn, pointer->PointerNew, context, pointer_new);
500 free_pointer_new_update(context, pointer_new);
505 case FASTPATH_UPDATETYPE_LARGE_POINTER:
511 up->stats.base[RDP_STATS_POINTER_LARGE]++;
512 rc = IFCALLRESULT(defaultReturn, pointer->PointerLarge, context, pointer_large);
513 free_pointer_large_update(context, pointer_large);
521 Stream_ResetPosition(s);
524 WLog_Print(fastpath->log, WLOG_ERROR,
"Fastpath update %s [%" PRIx8
"] failed, status %d",
525 fastpath_update_to_string(updateCode), updateCode, status);
537static int fastpath_recv_update_data(rdpFastPath* fastpath,
wStream* s)
542 BYTE fragmentation = 0;
543 BYTE compression = 0;
544 BYTE compressionFlags = 0;
546 const BYTE* pDstData =
nullptr;
551 rdpRdp* rdp = fastpath->rdp;
556 rdpTransport* transport = rdp->transport;
561 if (!fastpath_read_update_header(fastpath->log, s, &updateCode, &fragmentation, &compression))
564 if (compression == FASTPATH_OUTPUT_COMPRESSION_USED)
566 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 1))
569 Stream_Read_UINT8(s, compressionFlags);
572 compressionFlags = 0;
574 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 2))
577 Stream_Read_UINT16(s, size);
579 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, size))
582 const int bulkStatus =
583 bulk_decompress(rdp->bulk, Stream_Pointer(s), size, &pDstData, &DstSize, compressionFlags);
584 Stream_Seek(s, size);
588 WLog_Print(fastpath->log, WLOG_ERROR,
"bulk_decompress() failed");
592 if (!Stream_EnsureRemainingCapacity(fastpath->updateData, DstSize))
595 Stream_Write(fastpath->updateData, pDstData, DstSize);
597 if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
599 if (fastpath->fragmentation != -1)
601 WLog_Print(fastpath->log, WLOG_ERROR,
"Unexpected FASTPATH_FRAGMENT_SINGLE");
605 status = fastpath_recv_update(fastpath, updateCode, fastpath->updateData);
609 WLog_Print(fastpath->log, WLOG_ERROR,
"fastpath_recv_update() - %i", status);
615 rdpContext* context =
nullptr;
616 const size_t totalSize = Stream_GetPosition(fastpath->updateData);
618 context = transport_get_context(transport);
619 WINPR_ASSERT(context);
620 WINPR_ASSERT(context->settings);
626 fastpath->log, WLOG_ERROR,
627 "Total size (%" PRIuz
") exceeds MultifragMaxRequestSize (%" PRIu32
")", totalSize,
632 if (fragmentation == FASTPATH_FRAGMENT_FIRST)
634 if (fastpath->fragmentation != -1)
636 WLog_Print(fastpath->log, WLOG_ERROR,
"Unexpected FASTPATH_FRAGMENT_FIRST");
640 fastpath->fragmentation = FASTPATH_FRAGMENT_FIRST;
642 else if (fragmentation == FASTPATH_FRAGMENT_NEXT)
644 if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) &&
645 (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT))
647 WLog_Print(fastpath->log, WLOG_ERROR,
"Unexpected FASTPATH_FRAGMENT_NEXT");
651 fastpath->fragmentation = FASTPATH_FRAGMENT_NEXT;
653 else if (fragmentation == FASTPATH_FRAGMENT_LAST)
655 if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) &&
656 (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT))
658 WLog_Print(fastpath->log, WLOG_ERROR,
"Unexpected FASTPATH_FRAGMENT_LAST");
662 fastpath->fragmentation = -1;
663 status = fastpath_recv_update(fastpath, updateCode, fastpath->updateData);
667 WLog_Print(fastpath->log, WLOG_ERROR,
"fastpath_recv_update() - %i", status);
678state_run_t fastpath_recv_updates(rdpFastPath* fastpath,
wStream* s)
680 state_run_t rc = STATE_RUN_FAILED;
683 WINPR_ASSERT(fastpath);
684 WINPR_ASSERT(fastpath->rdp);
686 while (Stream_GetRemainingLength(s) >= 3)
688 if (fastpath_recv_update_data(fastpath, s) < 0)
690 WLog_Print(fastpath->log, WLOG_ERROR,
"fastpath_recv_update_data() fail");
691 rc = STATE_RUN_FAILED;
696 rc = STATE_RUN_SUCCESS;
703static BOOL fastpath_read_input_event_header(wLog* log,
wStream* s, BYTE* eventFlags,
706 BYTE eventHeader = 0;
709 WINPR_ASSERT(eventFlags);
710 WINPR_ASSERT(eventCode);
712 if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 1))
715 Stream_Read_UINT8(s, eventHeader);
716 *eventFlags = (eventHeader & 0x1F);
717 *eventCode = (eventHeader >> 5);
722static BOOL fastpath_recv_input_event_scancode(rdpFastPath* fastpath,
wStream* s, BYTE eventFlags)
724 WINPR_ASSERT(fastpath);
725 WINPR_ASSERT(fastpath->rdp);
726 WINPR_ASSERT(fastpath->rdp->input);
729 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 1))
732 rdpInput* input = fastpath->rdp->input;
734 const UINT8 code = Stream_Get_UINT8(s);
737 if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
738 flags |= KBD_FLAGS_RELEASE;
740 if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_EXTENDED))
741 flags |= KBD_FLAGS_EXTENDED;
743 if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_PREFIX_E1))
744 flags |= KBD_FLAGS_EXTENDED1;
747 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
749 return IFCALLRESULT(TRUE, input->KeyboardEvent, input, flags, code);
753static BOOL fastpath_recv_input_event_mouse(rdpFastPath* fastpath,
wStream* s,
754 WINPR_ATTR_UNUSED BYTE eventFlags)
756 UINT16 pointerFlags = 0;
759 WINPR_ASSERT(fastpath);
760 WINPR_ASSERT(fastpath->rdp);
761 WINPR_ASSERT(fastpath->rdp->input);
764 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 6))
767 rdpInput* input = fastpath->rdp->input;
770 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
773 Stream_Read_UINT16(s, pointerFlags);
774 Stream_Read_UINT16(s, xPos);
775 Stream_Read_UINT16(s, yPos);
776 return IFCALLRESULT(TRUE, input->MouseEvent, input, pointerFlags, xPos, yPos);
780static BOOL fastpath_recv_input_event_relmouse(rdpFastPath* fastpath,
wStream* s,
781 WINPR_ATTR_UNUSED BYTE eventFlags)
783 rdpInput* input =
nullptr;
784 UINT16 pointerFlags = 0;
787 WINPR_ASSERT(fastpath);
788 WINPR_ASSERT(fastpath->rdp);
789 WINPR_ASSERT(fastpath->rdp->context);
790 WINPR_ASSERT(fastpath->rdp->input);
793 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 6))
796 input = fastpath->rdp->input;
798 Stream_Read_UINT16(s, pointerFlags);
799 Stream_Read_INT16(s, xDelta);
800 Stream_Read_INT16(s, yDelta);
804 WLog_Print(fastpath->log, WLOG_ERROR,
805 "Received relative mouse event(flags=0x%04" PRIx16
", xPos=%" PRId16
806 ", yPos=%" PRId16
"), but we did not announce support for that",
807 pointerFlags, xDelta, yDelta);
812 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
814 return IFCALLRESULT(TRUE, input->RelMouseEvent, input, pointerFlags, xDelta, yDelta);
818static BOOL fastpath_recv_input_event_qoe(rdpFastPath* fastpath,
wStream* s,
819 WINPR_ATTR_UNUSED BYTE eventFlags)
821 WINPR_ASSERT(fastpath);
822 WINPR_ASSERT(fastpath->rdp);
823 WINPR_ASSERT(fastpath->rdp->context);
824 WINPR_ASSERT(fastpath->rdp->input);
827 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 4))
830 rdpInput* input = fastpath->rdp->input;
832 UINT32 timestampMS = 0;
833 Stream_Read_UINT32(s, timestampMS);
837 WLog_Print(fastpath->log, WLOG_ERROR,
838 "Received qoe event(timestamp=%" PRIu32
839 "ms), but we did not announce support for that",
845 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
847 return IFCALLRESULT(TRUE, input->QoEEvent, input, timestampMS);
851static BOOL fastpath_recv_input_event_mousex(rdpFastPath* fastpath,
wStream* s,
852 WINPR_ATTR_UNUSED BYTE eventFlags)
854 rdpInput* input =
nullptr;
855 UINT16 pointerFlags = 0;
859 WINPR_ASSERT(fastpath);
860 WINPR_ASSERT(fastpath->rdp);
861 WINPR_ASSERT(fastpath->rdp->context);
862 WINPR_ASSERT(fastpath->rdp->input);
865 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 6))
868 input = fastpath->rdp->input;
870 Stream_Read_UINT16(s, pointerFlags);
871 Stream_Read_UINT16(s, xPos);
872 Stream_Read_UINT16(s, yPos);
876 WLog_Print(fastpath->log, WLOG_ERROR,
877 "Received extended mouse event(flags=0x%04" PRIx16
", xPos=%" PRIu16
878 ", yPos=%" PRIu16
"), but we did not announce support for that",
879 pointerFlags, xPos, yPos);
884 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
887 return IFCALLRESULT(TRUE, input->ExtendedMouseEvent, input, pointerFlags, xPos, yPos);
891static BOOL fastpath_recv_input_event_sync(rdpFastPath* fastpath, WINPR_ATTR_UNUSED
wStream* s,
894 WINPR_ASSERT(fastpath);
895 WINPR_ASSERT(fastpath->rdp);
896 WINPR_ASSERT(fastpath->rdp->input);
899 rdpInput* input = fastpath->rdp->input;
902 if (!rdp_has_reached_state(input->context->rdp, CONNECTION_STATE_ACTIVE))
904 return IFCALLRESULT(TRUE, input->SynchronizeEvent, input, eventFlags);
908static BOOL fastpath_recv_input_event_unicode(rdpFastPath* fastpath,
wStream* s, BYTE eventFlags)
910 UINT16 unicodeCode = 0;
913 WINPR_ASSERT(fastpath);
916 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 2))
919 Stream_Read_UINT16(s, unicodeCode);
922 if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
923 flags |= KBD_FLAGS_RELEASE;
926 if (!rdp_has_reached_state(fastpath->rdp->input->context->rdp, CONNECTION_STATE_ACTIVE))
929 WINPR_ASSERT(fastpath->rdp);
930 WINPR_ASSERT(fastpath->rdp);
931 WINPR_ASSERT(fastpath->rdp->input);
932 return IFCALLRESULT(FALSE, fastpath->rdp->input->UnicodeKeyboardEvent, fastpath->rdp->input,
937static BOOL fastpath_recv_input_event(rdpFastPath* fastpath,
wStream* s)
942 WINPR_ASSERT(fastpath);
945 if (!rdp_is_active_state(fastpath->rdp))
947 WLog_Print(fastpath->log, WLOG_WARN,
"Input event before activation, ignoring");
951 if (!fastpath_read_input_event_header(fastpath->log, s, &eventFlags, &eventCode))
956 case FASTPATH_INPUT_EVENT_SCANCODE:
957 if (!fastpath_recv_input_event_scancode(fastpath, s, eventFlags))
962 case FASTPATH_INPUT_EVENT_MOUSE:
963 if (!fastpath_recv_input_event_mouse(fastpath, s, eventFlags))
968 case FASTPATH_INPUT_EVENT_MOUSEX:
969 if (!fastpath_recv_input_event_mousex(fastpath, s, eventFlags))
974 case FASTPATH_INPUT_EVENT_SYNC:
975 if (!fastpath_recv_input_event_sync(fastpath, s, eventFlags))
980 case FASTPATH_INPUT_EVENT_UNICODE:
981 if (!fastpath_recv_input_event_unicode(fastpath, s, eventFlags))
986 case TS_FP_RELPOINTER_EVENT:
987 if (!fastpath_recv_input_event_relmouse(fastpath, s, eventFlags))
992 case TS_FP_QOETIMESTAMP_EVENT:
993 if (!fastpath_recv_input_event_qoe(fastpath, s, eventFlags))
998 WLog_Print(fastpath->log, WLOG_ERROR,
"Unknown eventCode %" PRIu8
"", eventCode);
1005state_run_t fastpath_recv_inputs(rdpFastPath* fastpath,
wStream* s)
1007 WINPR_ASSERT(fastpath);
1010 if (fastpath->numberEvents == 0)
1016 if (!Stream_CheckAndLogRequiredLengthWLog(fastpath->log, s, 1))
1017 return STATE_RUN_FAILED;
1019 Stream_Read_UINT8(s, fastpath->numberEvents);
1022 for (BYTE i = 0; i < fastpath->numberEvents; i++)
1024 if (!fastpath_recv_input_event(fastpath, s))
1025 return STATE_RUN_FAILED;
1028 return STATE_RUN_SUCCESS;
1032static UINT32 fastpath_get_sec_bytes(rdpRdp* rdp)
1034 UINT32 sec_bytes = 0;
1044 ENCRYPTION_METHOD_FIPS)
1051wStream* fastpath_input_pdu_init_header(rdpFastPath* fastpath, UINT16* sec_flags)
1053 if (!fastpath || !fastpath->rdp)
1056 rdpRdp* rdp = fastpath->rdp;
1057 wStream* s = transport_send_stream_init(rdp->transport, 256);
1066 *sec_flags |= SEC_ENCRYPT;
1068 if (rdp->do_secure_checksum)
1069 *sec_flags |= SEC_SECURE_CHECKSUM;
1072 Stream_Seek(s, fastpath_get_sec_bytes(rdp));
1076wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE eventCode,
1080 s = fastpath_input_pdu_init_header(fastpath, sec_flags);
1085 WINPR_ASSERT(eventCode < 8);
1086 WINPR_ASSERT(eventFlags < 0x20);
1087 Stream_Write_UINT8(s, (UINT8)(eventFlags | (eventCode << 5)));
1091BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath,
wStream* s,
size_t iNumEvents,
1095 BYTE eventHeader = 0;
1096 BOOL should_unlock = FALSE;
1107 rdpRdp* rdp = fastpath->rdp;
1110 WINPR_ASSERT(iNumEvents > 0);
1112 const CONNECTION_STATE state = rdp_get_state(rdp);
1113 if (!rdp_is_active_state(rdp))
1115 if (!rdp->was_deactivated)
1117 WLog_Print(fastpath->log, WLOG_WARN,
"called before activation [%s]",
1118 rdp_state_string(state));
1122 WLog_Print(fastpath->log, WLOG_DEBUG,
1123 "called during deactivate-reactivate [%s], ignoring",
1124 rdp_state_string(state));
1135 if (iNumEvents > 15)
1139 size_t length = Stream_GetPosition(s);
1141 if (length >= (2u << 14))
1143 WLog_Print(fastpath->log, WLOG_ERROR,
"Maximum FastPath PDU length is 32767");
1147 eventHeader = FASTPATH_INPUT_ACTION_FASTPATH;
1148 eventHeader |= (iNumEvents << 2);
1150 if (sec_flags & SEC_ENCRYPT)
1151 eventHeader |= (FASTPATH_INPUT_ENCRYPTED << 6);
1153 if (sec_flags & SEC_SECURE_CHECKSUM)
1154 eventHeader |= (FASTPATH_INPUT_SECURE_CHECKSUM << 6);
1156 Stream_ResetPosition(s);
1157 Stream_Write_UINT8(s, eventHeader);
1161 if (sec_flags & SEC_ENCRYPT)
1164 should_unlock = TRUE;
1166 const size_t sec_bytes = fastpath_get_sec_bytes(fastpath->rdp);
1167 if (sec_bytes + 3ULL > length)
1170 BYTE* fpInputEvents = Stream_PointerAs(s, BYTE) + sec_bytes;
1171 const UINT16 fpInputEvents_length = (UINT16)(length - 3 - sec_bytes);
1173 WINPR_ASSERT(rdp->settings);
1175 ENCRYPTION_METHOD_FIPS)
1179 if ((pad = 8 - (fpInputEvents_length % 8)) == 8)
1182 if (!Stream_CheckAndLogRequiredCapacityWLog(fastpath->log, s, 4))
1185 Stream_Write_UINT16(s, 0x10);
1186 Stream_Write_UINT8(s, 0x1);
1187 Stream_Write_UINT8(s, pad);
1189 if (!Stream_CheckAndLogRequiredCapacityWLog(
1190 fastpath->log, s, 1ull * fpInputEvents_length + sec_bytes + pad + 8ull))
1193 if (!security_hmac_signature(fpInputEvents, fpInputEvents_length, Stream_Pointer(s),
1198 memset(fpInputEvents + fpInputEvents_length, 0, pad);
1200 if (!security_fips_encrypt(fpInputEvents, fpInputEvents_length + pad, rdp))
1208 if (!Stream_CheckAndLogRequiredCapacityWLog(fastpath->log, s, 8))
1210 if (sec_flags & SEC_SECURE_CHECKSUM)
1211 res = security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length,
1212 TRUE, Stream_Pointer(s), 8);
1214 res = security_mac_signature(rdp, fpInputEvents, fpInputEvents_length,
1215 Stream_Pointer(s), 8);
1217 if (!res || !security_encrypt(fpInputEvents, fpInputEvents_length, rdp))
1228 WINPR_ASSERT(length < UINT16_MAX);
1229 if (!Stream_SetPosition(s, 1))
1231 Stream_Write_UINT16_BE(s, 0x8000 | (UINT16)length);
1232 if (!Stream_SetPosition(s, length))
1234 Stream_SealLength(s);
1237 if (transport_write(rdp->transport, s) < 0)
1243 security_unlock(rdp);
1248BOOL fastpath_send_input_pdu(rdpFastPath* fastpath,
wStream* s, UINT16 sec_flags)
1250 return fastpath_send_multiple_input_pdu(fastpath, s, 1, sec_flags);
1253wStream* fastpath_update_pdu_init(rdpFastPath* fastpath)
1255 return transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE);
1258wStream* fastpath_update_pdu_init_new(WINPR_ATTR_UNUSED rdpFastPath* fastpath)
1261 s = Stream_New(
nullptr, FASTPATH_MAX_PACKET_SIZE);
1265BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode,
wStream* s,
1266 BOOL skipCompression)
1270 rdpSettings* settings =
nullptr;
1271 rdpRdp* rdp =
nullptr;
1272 UINT32 fpHeaderSize = 6;
1273 UINT32 fpUpdatePduHeaderSize = 0;
1274 UINT32 fpUpdateHeaderSize = 0;
1277 UINT16 sec_flags = 0;
1279 if (!fastpath || !fastpath->rdp || !fastpath->fs || !s)
1282 rdp = fastpath->rdp;
1284 settings = rdp->settings;
1289 UINT16 maxLength = FASTPATH_MAX_PACKET_SIZE - 20;
1293 const UINT16 CompressionMaxSize = bulk_compression_max_size(rdp->bulk);
1294 maxLength = (maxLength < CompressionMaxSize) ? maxLength : CompressionMaxSize;
1298 size_t totalLength = Stream_GetPosition(s);
1299 Stream_ResetPosition(s);
1304 WLog_Print(fastpath->log, WLOG_ERROR,
"client does not support fast path output");
1311 WLog_Print(fastpath->log, WLOG_ERROR,
1312 "fast path update size (%" PRIuz
1313 ") exceeds the client's maximum request size (%" PRIu32
")",
1321 sec_flags |= SEC_ENCRYPT;
1323 if (rdp->do_secure_checksum)
1324 sec_flags |= SEC_SECURE_CHECKSUM;
1327 for (
int fragment = 0; (totalLength > 0) || (fragment == 0); fragment++)
1330 const BYTE* pDstData =
nullptr;
1331 UINT32 compressionFlags = 0;
1333 BYTE* pSignature =
nullptr;
1334 fpUpdatePduHeader.action = 0;
1335 fpUpdatePduHeader.secFlags = 0;
1336 fpUpdateHeader.compression = 0;
1337 fpUpdateHeader.compressionFlags = 0;
1338 fpUpdateHeader.updateCode = updateCode;
1339 fpUpdateHeader.size = (UINT16)(totalLength > maxLength) ? maxLength : (UINT16)totalLength;
1340 const BYTE* pSrcData = Stream_Pointer(s);
1341 UINT32 SrcSize = DstSize = fpUpdateHeader.size;
1342 BOOL should_unlock = FALSE;
1344 if (sec_flags & SEC_ENCRYPT)
1345 fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_ENCRYPTED;
1347 if (sec_flags & SEC_SECURE_CHECKSUM)
1348 fpUpdatePduHeader.secFlags |= FASTPATH_OUTPUT_SECURE_CHECKSUM;
1352 if (bulk_compress(rdp->bulk, pSrcData, SrcSize, &pDstData, &DstSize,
1353 &compressionFlags) >= 0)
1355 if (compressionFlags)
1357 WINPR_ASSERT(compressionFlags <= UINT8_MAX);
1358 fpUpdateHeader.compressionFlags = (UINT8)compressionFlags;
1359 fpUpdateHeader.compression = FASTPATH_OUTPUT_COMPRESSION_USED;
1364 if (!fpUpdateHeader.compression)
1366 pDstData = Stream_Pointer(s);
1367 DstSize = fpUpdateHeader.size;
1370 if (DstSize > UINT16_MAX)
1372 fpUpdateHeader.size = (UINT16)DstSize;
1373 totalLength -= SrcSize;
1375 if (totalLength == 0)
1376 fpUpdateHeader.fragmentation =
1377 (fragment == 0) ? FASTPATH_FRAGMENT_SINGLE : FASTPATH_FRAGMENT_LAST;
1379 fpUpdateHeader.fragmentation =
1380 (fragment == 0) ? FASTPATH_FRAGMENT_FIRST : FASTPATH_FRAGMENT_NEXT;
1382 fpUpdateHeaderSize = fastpath_get_update_header_size(&fpUpdateHeader);
1383 fpUpdatePduHeaderSize = fastpath_get_update_pdu_header_size(&fpUpdatePduHeader, rdp);
1384 fpHeaderSize = fpUpdateHeaderSize + fpUpdatePduHeaderSize;
1386 if (sec_flags & SEC_ENCRYPT)
1388 pSignature = Stream_Buffer(fs) + 3;
1391 ENCRYPTION_METHOD_FIPS)
1395 if ((pad = 8 - ((DstSize + fpUpdateHeaderSize) % 8)) == 8)
1398 fpUpdatePduHeader.fipsInformation[0] = 0x10;
1399 fpUpdatePduHeader.fipsInformation[1] = 0x00;
1400 fpUpdatePduHeader.fipsInformation[2] = 0x01;
1401 fpUpdatePduHeader.fipsInformation[3] = pad;
1405 const size_t len = fpUpdateHeader.size + fpHeaderSize + pad;
1406 if (len > UINT16_MAX)
1409 fpUpdatePduHeader.length = (UINT16)len;
1410 Stream_ResetPosition(fs);
1411 if (!fastpath_write_update_pdu_header(fastpath->log, fs, &fpUpdatePduHeader, rdp))
1413 if (!fastpath_write_update_header(fastpath->log, fs, &fpUpdateHeader))
1416 if (!Stream_CheckAndLogRequiredCapacityWLog(fastpath->log, (fs), (
size_t)DstSize + pad))
1418 Stream_Write(fs, pDstData, DstSize);
1421 Stream_Zero(fs, pad);
1424 if (sec_flags & SEC_ENCRYPT)
1428 should_unlock = TRUE;
1429 UINT32 dataSize = fpUpdateHeaderSize + DstSize + pad;
1430 BYTE* data = Stream_PointerAs(fs, BYTE) - dataSize;
1433 ENCRYPTION_METHOD_FIPS)
1436 if (!security_hmac_signature(data, dataSize - pad, pSignature, 8, rdp))
1439 if (!security_fips_encrypt(data, dataSize, rdp))
1445 if (sec_flags & SEC_SECURE_CHECKSUM)
1447 security_salted_mac_signature(rdp, data, dataSize, TRUE, pSignature, 8);
1449 status = security_mac_signature(rdp, data, dataSize, pSignature, 8);
1451 if (!status || !security_encrypt(data, dataSize, rdp))
1457 Stream_SealLength(fs);
1459 if (transport_write(rdp->transport, fs) < 0)
1466 security_unlock(rdp);
1468 if (!res || !status)
1471 Stream_Seek(s, SrcSize);
1477rdpFastPath* fastpath_new(rdpRdp* rdp)
1481 rdpFastPath* fastpath = (rdpFastPath*)calloc(1,
sizeof(rdpFastPath));
1485 fastpath->log = WLog_Get(FTAG);
1486 fastpath->rdp = rdp;
1487 fastpath->fragmentation = -1;
1488 fastpath->fs = Stream_New(
nullptr, FASTPATH_MAX_PACKET_SIZE);
1489 fastpath->updateData = Stream_New(
nullptr, FASTPATH_MAX_PACKET_SIZE);
1491 if (!fastpath->fs || !fastpath->updateData)
1496 fastpath_free(fastpath);
1500void fastpath_free(rdpFastPath* fastpath)
1504 Stream_Free(fastpath->updateData, TRUE);
1505 Stream_Free(fastpath->fs, TRUE);
1510BYTE fastpath_get_encryption_flags(rdpFastPath* fastpath)
1512 WINPR_ASSERT(fastpath);
1513 return fastpath->encryptionFlags;
1516BOOL fastpath_decrypt(rdpFastPath* fastpath,
wStream* s, UINT16* length)
1518 WINPR_ASSERT(fastpath);
1519 if (fastpath_get_encryption_flags(fastpath) & FASTPATH_OUTPUT_ENCRYPTED)
1521 const UINT16 flags =
1522 (fastpath_get_encryption_flags(fastpath) & FASTPATH_OUTPUT_SECURE_CHECKSUM)
1523 ? SEC_SECURE_CHECKSUM
1526 if (!rdp_decrypt(fastpath->rdp, s, length, flags))
WINPR_ATTR_NODISCARD FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
WINPR_ATTR_NODISCARD FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.