freerdp: merge with master
[platform/upstream/freerdp.git] / libfreerdp / core / fastpath.c
index 50e1ab0..a02e8d9 100644 (file)
 #include <string.h>
 
 #include <winpr/crt.h>
+#include <winpr/stream.h>
 
 #include <freerdp/api.h>
 #include <freerdp/crypto/per.h>
-#include <winpr/stream.h>
 
 #include "orders.h"
 #include "update.h"
@@ -76,9 +76,9 @@ UINT16 fastpath_header_length(wStream* s)
 {
        BYTE length1;
 
-       stream_seek_BYTE(s);
+       Stream_Seek_BYTE(s);
        stream_read_BYTE(s, length1);
-       stream_rewind(s, 2);
+       Stream_Rewind(s, 2);
 
        return ((length1 & 0x80) != 0 ? 3 : 2);
 }
@@ -96,7 +96,7 @@ UINT16 fastpath_read_header(rdpFastPath* fastpath, wStream* s)
 
        stream_read_BYTE(s, header);
 
-       if (fastpath != NULL)
+       if (fastpath)
        {
                fastpath->encryptionFlags = (header & 0xC0) >> 6;
                fastpath->numberEvents = (header & 0x3C) >> 2;
@@ -133,7 +133,7 @@ BOOL fastpath_read_header_rdp(rdpFastPath* fastpath, wStream* s, UINT16 *length)
 
        stream_read_BYTE(s, header);
 
-       if (fastpath != NULL)
+       if (fastpath)
        {
                fastpath->encryptionFlags = (header & 0xC0) >> 6;
                fastpath->numberEvents = (header & 0x3C) >> 2;
@@ -142,7 +142,7 @@ BOOL fastpath_read_header_rdp(rdpFastPath* fastpath, wStream* s, UINT16 *length)
        if (!per_read_length(s, length))
                return FALSE;
 
-       *length = *length - stream_get_length(s);
+       *length = *length - Stream_GetPosition(s);
        return TRUE;
 }
 
@@ -157,6 +157,7 @@ static BOOL fastpath_recv_orders(rdpFastPath* fastpath, wStream* s)
        {
                if (!update_recv_order(update, s))
                        return FALSE;
+
                numberOrders--;
        }
 
@@ -169,7 +170,7 @@ static BOOL fastpath_recv_update_common(rdpFastPath* fastpath, wStream* s)
        rdpUpdate* update = fastpath->rdp->update;
        rdpContext* context = update->context;
 
-       if (stream_get_left(s) < 2)
+       if (Stream_GetRemainingLength(s) < 2)
                return FALSE;
 
        stream_read_UINT16(s, updateType); /* updateType (2 bytes) */
@@ -278,24 +279,40 @@ static int fastpath_recv_update(rdpFastPath* fastpath, BYTE updateCode, UINT32 s
        return status;
 }
 
+const char* fastpath_get_fragmentation_string(BYTE fragmentation)
+{
+       if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
+               return "FASTPATH_FRAGMENT_SINGLE";
+       else if (fragmentation == FASTPATH_FRAGMENT_LAST)
+               return "FASTPATH_FRAGMENT_LAST";
+       else if (fragmentation == FASTPATH_FRAGMENT_FIRST)
+               return "FASTPATH_FRAGMENT_FIRST";
+       else if (fragmentation == FASTPATH_FRAGMENT_NEXT)
+               return "FASTPATH_FRAGMENT_NEXT";
+
+       return "FASTPATH_FRAGMENT_UNKNOWN";
+}
+
 static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
 {
        int status;
        UINT16 size;
+       UINT32 roff;
+       UINT32 rlen;
+       rdpRdp* rdp;
        int next_pos;
+       BYTE* buffer;
+       wStream* cs;
        UINT32 totalSize;
        BYTE updateCode;
        BYTE fragmentation;
        BYTE compression;
        BYTE compressionFlags;
-       wStream* update_stream;
-       wStream* comp_stream;
-       rdpRdp* rdp;
-       UINT32 roff;
-       UINT32 rlen;
+       rdpTransport* transport;
 
        status = 0;
        rdp = fastpath->rdp;
+       transport = fastpath->rdp->transport;
 
        fastpath_read_update_header(s, &updateCode, &fragmentation, &compression);
 
@@ -306,70 +323,137 @@ static int fastpath_recv_update_data(rdpFastPath* fastpath, wStream* s)
 
        stream_read_UINT16(s, size);
 
-       if (stream_get_left(s) < size)
+       if (Stream_GetRemainingLength(s) < size)
                return -1;
 
-       next_pos = stream_get_pos(s) + size;
-       comp_stream = s;
+       cs = s;
+       next_pos = Stream_GetPosition(s) + size;
 
        if (compressionFlags & PACKET_COMPRESSED)
        {
                if (decompress_rdp(rdp->mppc_dec, s->pointer, size, compressionFlags, &roff, &rlen))
                {
-                       comp_stream = stream_new(0);
-                       comp_stream->buffer = rdp->mppc_dec->history_buf + roff;
-                       comp_stream->pointer = comp_stream->buffer;
-                       comp_stream->capacity = rlen;
-                       size = comp_stream->capacity;
+                       size = rlen;
+                       buffer = rdp->mppc_dec->history_buf + roff;
+
+                       cs = StreamPool_Take(transport->ReceivePool, size);
+
+                       Stream_SetPosition(cs, 0);
+                       Stream_Write(cs, buffer, size);
+                       Stream_SealLength(cs);
+                       Stream_SetPosition(cs, 0);
                }
                else
                {
                        fprintf(stderr, "decompress_rdp() failed\n");
-                       stream_seek(s, size);
+                       Stream_Seek(s, size);
                }
        }
 
-       update_stream = NULL;
-
        if (fragmentation == FASTPATH_FRAGMENT_SINGLE)
        {
+               if (fastpath->fragmentation != -1)
+               {
+                       fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_SINGLE\n");
+                       return -1;
+               }
+
                totalSize = size;
-               update_stream = comp_stream;
+               status = fastpath_recv_update(fastpath, updateCode, totalSize, cs);
+
+               if (status < 0)
+                       return -1;
        }
        else
        {
                if (fragmentation == FASTPATH_FRAGMENT_FIRST)
-                       stream_set_pos(fastpath->updateData, 0);
+               {
+                       if (fastpath->fragmentation != -1)
+                       {
+                               fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_FIRST\n");
+                               return -1;
+                       }
 
-               stream_check_size(fastpath->updateData, size);
-               stream_copy(fastpath->updateData, comp_stream, size);
+                       fastpath->fragmentation = FASTPATH_FRAGMENT_FIRST;
 
-               if (stream_get_length(fastpath->updateData) > rdp->settings->MultifragMaxRequestSize)
-               {
-                       fprintf(stderr, "fastpath PDU is bigger than MultifragMaxRequestSize\n");
-                       return -1;
-               }
+                       totalSize = size;
 
-               if (fragmentation == FASTPATH_FRAGMENT_LAST)
+                       if (totalSize > transport->settings->MultifragMaxRequestSize)
+                       {
+                               fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n",
+                                               totalSize, transport->settings->MultifragMaxRequestSize);
+                               return -1;
+                       }
+
+                       fastpath->updateData = StreamPool_Take(transport->ReceivePool, size);
+                       Stream_SetPosition(fastpath->updateData, 0);
+
+                       Stream_Copy(fastpath->updateData, cs, size);
+               }
+               else if (fragmentation == FASTPATH_FRAGMENT_NEXT)
                {
-                       update_stream = fastpath->updateData;
-                       totalSize = stream_get_length(update_stream);
-                       stream_set_pos(update_stream, 0);
+                       if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) &&
+                                       (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT))
+                       {
+                               fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_NEXT\n");
+                               return -1;
+                       }
+
+                       fastpath->fragmentation = FASTPATH_FRAGMENT_NEXT;
+
+                       totalSize = Stream_GetPosition(fastpath->updateData) + size;
+
+                       if (totalSize > transport->settings->MultifragMaxRequestSize)
+                       {
+                               fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n",
+                                               totalSize, transport->settings->MultifragMaxRequestSize);
+                               return -1;
+                       }
+
+                       Stream_EnsureCapacity(fastpath->updateData, totalSize);
+
+                       Stream_Copy(fastpath->updateData, cs, size);
                }
-       }
+               else if (fragmentation == FASTPATH_FRAGMENT_LAST)
+               {
+                       if ((fastpath->fragmentation != FASTPATH_FRAGMENT_FIRST) &&
+                                       (fastpath->fragmentation != FASTPATH_FRAGMENT_NEXT))
+                       {
+                               fprintf(stderr, "Unexpected FASTPATH_FRAGMENT_LAST\n");
+                               return -1;
+                       }
 
-       if (update_stream)
-       {
-               status = fastpath_recv_update(fastpath, updateCode, totalSize, update_stream);
+                       fastpath->fragmentation = -1;
 
-               if (status < 0)
-                       return -1;
+                       totalSize = Stream_GetPosition(fastpath->updateData) + size;
+
+                       if (totalSize > transport->settings->MultifragMaxRequestSize)
+                       {
+                               fprintf(stderr, "Total size (%d) exceeds MultifragMaxRequestSize (%d)\n",
+                                               totalSize, transport->settings->MultifragMaxRequestSize);
+                               return -1;
+                       }
+
+                       Stream_EnsureCapacity(fastpath->updateData, totalSize);
+
+                       Stream_Copy(fastpath->updateData, cs, size);
+
+                       Stream_SealLength(fastpath->updateData);
+                       Stream_SetPosition(fastpath->updateData, 0);
+
+                       status = fastpath_recv_update(fastpath, updateCode, totalSize, fastpath->updateData);
+
+                       Stream_Release(fastpath->updateData);
+
+                       if (status < 0)
+                               return -1;
+               }
        }
 
-       stream_set_pos(s, next_pos);
+       Stream_SetPosition(s, next_pos);
 
-       if (comp_stream != s)
-               free(comp_stream);
+       if (cs != s)
+               Stream_Release(cs);
 
        return status;
 }
@@ -381,7 +465,7 @@ int fastpath_recv_updates(rdpFastPath* fastpath, wStream* s)
 
        IFCALL(update->BeginPaint, update->context);
 
-       while (stream_get_left(s) >= 3)
+       while (Stream_GetRemainingLength(s) >= 3)
        {
                if (fastpath_recv_update_data(fastpath, s) < 0)
                        return -1;
@@ -396,7 +480,7 @@ static BOOL fastpath_read_input_event_header(wStream* s, BYTE* eventFlags, BYTE*
 {
        BYTE eventHeader;
 
-       if (stream_get_left(s) < 1)
+       if (Stream_GetRemainingLength(s) < 1)
                return FALSE;
 
        stream_read_BYTE(s, eventHeader); /* eventHeader (1 byte) */
@@ -412,12 +496,13 @@ static BOOL fastpath_recv_input_event_scancode(rdpFastPath* fastpath, wStream* s
        UINT16 flags;
        UINT16 code;
 
-       if (stream_get_left(s) < 1)
+       if (Stream_GetRemainingLength(s) < 1)
                return FALSE;
 
        stream_read_BYTE(s, code); /* keyCode (1 byte) */
 
        flags = 0;
+
        if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
                flags |= KBD_FLAGS_RELEASE;
        else
@@ -437,7 +522,7 @@ static BOOL fastpath_recv_input_event_mouse(rdpFastPath* fastpath, wStream* s, B
        UINT16 xPos;
        UINT16 yPos;
 
-       if (stream_get_left(s) < 6)
+       if (Stream_GetRemainingLength(s) < 6)
                return FALSE;
 
        stream_read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
@@ -455,7 +540,7 @@ static BOOL fastpath_recv_input_event_mousex(rdpFastPath* fastpath, wStream* s,
        UINT16 xPos;
        UINT16 yPos;
 
-       if (stream_get_left(s) < 6)
+       if (Stream_GetRemainingLength(s) < 6)
                return FALSE;
 
        stream_read_UINT16(s, pointerFlags); /* pointerFlags (2 bytes) */
@@ -479,12 +564,13 @@ static BOOL fastpath_recv_input_event_unicode(rdpFastPath* fastpath, wStream* s,
        UINT16 unicodeCode;
        UINT16 flags;
 
-       if (stream_get_left(s) < 2)
+       if (Stream_GetRemainingLength(s) < 2)
                return FALSE;
 
        stream_read_UINT16(s, unicodeCode); /* unicodeCode (2 bytes) */
 
        flags = 0;
+
        if ((eventFlags & FASTPATH_INPUT_KBDFLAGS_RELEASE))
                flags |= KBD_FLAGS_RELEASE;
        else
@@ -549,7 +635,7 @@ int fastpath_recv_inputs(rdpFastPath* fastpath, wStream* s)
                 * as one additional byte here.
                 */
 
-               if (stream_get_left(s) < 1)
+               if (Stream_GetRemainingLength(s) < 1)
                        return -1;
 
                stream_read_BYTE(s, fastpath->numberEvents); /* eventHeader (1 byte) */
@@ -568,14 +654,16 @@ static UINT32 fastpath_get_sec_bytes(rdpRdp* rdp)
 {
        UINT32 sec_bytes;
 
+       sec_bytes = 0;
+
        if (rdp->do_crypt)
        {
                sec_bytes = 8;
+
                if (rdp->settings->EncryptionMethods == ENCRYPTION_METHOD_FIPS)
                        sec_bytes += 4;
        }
-       else
-               sec_bytes = 0;
+
        return sec_bytes;
 }
 
@@ -587,15 +675,18 @@ wStream* fastpath_input_pdu_init_header(rdpFastPath* fastpath)
        rdp = fastpath->rdp;
 
        s = transport_send_stream_init(rdp->transport, 256);
-       stream_seek(s, 3); /* fpInputHeader, length1 and length2 */
+
+       Stream_Seek(s, 3); /* fpInputHeader, length1 and length2 */
 
        if (rdp->do_crypt)
        {
                rdp->sec_flags |= SEC_ENCRYPT;
+
                if (rdp->do_secure_checksum)
                        rdp->sec_flags |= SEC_SECURE_CHECKSUM;
        }
-       stream_seek(s, fastpath_get_sec_bytes(rdp));
+
+       Stream_Seek(s, fastpath_get_sec_bytes(rdp));
 
        return s;
 }
@@ -609,6 +700,7 @@ wStream* fastpath_input_pdu_init(rdpFastPath* fastpath, BYTE eventFlags, BYTE ev
 
        s = fastpath_input_pdu_init_header(fastpath);
        stream_write_BYTE(s, eventFlags | (eventCode << 5)); /* eventHeader (1 byte) */
+
        return s;
 }
 
@@ -621,7 +713,8 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu
 
        rdp = fastpath->rdp;
 
-       length = stream_get_length(s);
+       length = Stream_GetPosition(s);
+
        if (length >= (2 << 14))
        {
                fprintf(stderr, "Maximum FastPath PDU length is 32767\n");
@@ -629,17 +722,23 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu
        }
 
        eventHeader = FASTPATH_INPUT_ACTION_FASTPATH;
+<<<<<<< HEAD
+       eventHeader |= (1 << 2); /* numberEvents */
+
+=======
        eventHeader |= (iNumEvents << 2); /* numberEvents */
+>>>>>>> f1672948ff0b5f6a9d3cda658a18104df3c3d1e4
        if (rdp->sec_flags & SEC_ENCRYPT)
                eventHeader |= (FASTPATH_INPUT_ENCRYPTED << 6);
        if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
                eventHeader |= (FASTPATH_INPUT_SECURE_CHECKSUM << 6);
 
-       stream_set_pos(s, 0);
+       Stream_SetPosition(s, 0);
        stream_write_BYTE(s, eventHeader);
        sec_bytes = fastpath_get_sec_bytes(fastpath->rdp);
+
        /*
-        * We always encode length in two bytes, eventhough we could use
+        * We always encode length in two bytes, even though we could use
         * only one byte if length <= 0x7F. It is just easier that way,
         * because we can leave room for fixed-length header, store all
         * the data first and then store the header.
@@ -651,18 +750,21 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, int iNu
                BYTE* fpInputEvents;
                UINT16 fpInputEvents_length;
 
-               fpInputEvents = stream_get_tail(s) + sec_bytes;
+               fpInputEvents = Stream_Pointer(s) + sec_bytes;
                fpInputEvents_length = length - 3 - sec_bytes;
+
                if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
-                       security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length, TRUE, stream_get_tail(s));
+                       security_salted_mac_signature(rdp, fpInputEvents, fpInputEvents_length, TRUE, Stream_Pointer(s));
                else
-                       security_mac_signature(rdp, fpInputEvents, fpInputEvents_length, stream_get_tail(s));
+                       security_mac_signature(rdp, fpInputEvents, fpInputEvents_length, Stream_Pointer(s));
+
                security_encrypt(fpInputEvents, fpInputEvents_length, rdp);
        }
 
        rdp->sec_flags = 0;
 
-       stream_set_pos(s, length);
+       Stream_SetPosition(s, length);
+
        if (transport_write(fastpath->rdp->transport, s) < 0)
                return FALSE;
 
@@ -677,10 +779,13 @@ BOOL fastpath_send_input_pdu(rdpFastPath* fastpath, wStream* s)
 wStream* fastpath_update_pdu_init(rdpFastPath* fastpath)
 {
        wStream* s;
+
        s = transport_send_stream_init(fastpath->rdp->transport, FASTPATH_MAX_PACKET_SIZE);
-       stream_seek(s, 3); /* fpOutputHeader, length1 and length2 */
-       stream_seek(s, fastpath_get_sec_bytes(fastpath->rdp));
-       stream_seek(s, 3); /* updateHeader, size */
+
+       Stream_Seek(s, 3); /* fpOutputHeader, length1 and length2 */
+       Stream_Seek(s, fastpath_get_sec_bytes(fastpath->rdp));
+       Stream_Seek(s, 3); /* updateHeader, size */
+
        return s;
 }
 
@@ -714,13 +819,13 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
        rdp = fastpath->rdp;
        sec_bytes = fastpath_get_sec_bytes(rdp);
        maxLength = FASTPATH_MAX_PACKET_SIZE - (6 + sec_bytes);
-       totalLength = stream_get_length(s) - (6 + sec_bytes);
-       stream_set_pos(s, 0);
+       totalLength = Stream_GetPosition(s) - (6 + sec_bytes);
+       Stream_SetPosition(s, 0);
        update = stream_new(0);
        try_comp = rdp->settings->CompressionEnabled;
        comp_update = stream_new(0);
 
-       for (fragment = 0; totalLength > 0 || fragment == 0; fragment++)
+       for (fragment = 0; (totalLength > 0) || (fragment == 0); fragment++)
        {
                stream_get_mark(s, holdp);
                ls = s;
@@ -729,6 +834,7 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
                comp_flags = 0;
                header_bytes = 6 + sec_bytes;
                pdu_data_bytes = dlen;
+
                if (try_comp)
                {
                        if (compress_rdp(rdp->mppc_enc, ls->pointer + header_bytes, dlen))
@@ -745,7 +851,9 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
                                }
                        }
                        else
+                       {
                                fprintf(stderr, "fastpath_send_update_pdu: mppc_encode failed\n");
+                       }
                }
 
                totalLength -= dlen;
@@ -758,14 +866,16 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
 
                stream_get_mark(ls, bm);
                header = 0;
+
                if (sec_bytes > 0)
                        header |= (FASTPATH_OUTPUT_ENCRYPTED << 6);
+
                stream_write_BYTE(ls, header); /* fpOutputHeader (1 byte) */
                stream_write_BYTE(ls, 0x80 | (pduLength >> 8)); /* length1 */
                stream_write_BYTE(ls, pduLength & 0xFF); /* length2 */
 
                if (sec_bytes > 0)
-                       stream_seek(ls, sec_bytes);
+                       Stream_Seek(ls, sec_bytes);
 
                fastpath_write_update_header(ls, updateCode, fragmentation, comp_flags);
 
@@ -776,22 +886,26 @@ BOOL fastpath_send_update_pdu(rdpFastPath* fastpath, BYTE updateCode, wStream* s
                        bytes_to_crypt = pdu_data_bytes + 4;
                }
                else
+               {
                        bytes_to_crypt = pdu_data_bytes + 3;
+               }
 
                stream_write_UINT16(ls, pdu_data_bytes);
 
                stream_attach(update, bm, pduLength);
-               stream_seek(update, pduLength);
+               Stream_Seek(update, pduLength);
 
                if (sec_bytes > 0)
                {
                        /* does this work ? */
                        ptr_to_crypt = bm + 3 + sec_bytes;
                        ptr_sig = bm + 3;
+
                        if (rdp->sec_flags & SEC_SECURE_CHECKSUM)
                                security_salted_mac_signature(rdp, ptr_to_crypt, bytes_to_crypt, TRUE, ptr_sig);
                        else
                                security_mac_signature(rdp, ptr_to_crypt, bytes_to_crypt, ptr_sig);
+
                        security_encrypt(ptr_to_crypt, bytes_to_crypt, rdp);
                }
 
@@ -818,16 +932,22 @@ rdpFastPath* fastpath_new(rdpRdp* rdp)
        rdpFastPath* fastpath;
 
        fastpath = (rdpFastPath*) malloc(sizeof(rdpFastPath));
-       ZeroMemory(fastpath, sizeof(rdpFastPath));
 
-       fastpath->rdp = rdp;
-       fastpath->updateData = stream_new(4096);
+       if (fastpath)
+       {
+               ZeroMemory(fastpath, sizeof(rdpFastPath));
+
+               fastpath->rdp = rdp;
+               fastpath->fragmentation = -1;
+       }
 
        return fastpath;
 }
 
 void fastpath_free(rdpFastPath* fastpath)
 {
-       stream_free(fastpath->updateData);
-       free(fastpath);
+       if (fastpath)
+       {
+               free(fastpath);
+       }
 }