The RDPUDP_ACK_VECTOR_HEADER structure contains the ACK vector (section 2.2.3.1) that specifies the states of the datagram in the receiver’s queue. This vector is a variable-size array. The states are encoded by using run-length encoding (RLE) and are stored in this array.
Example #1
0
        /// <summary>
        /// Create RDPUDP_ACK_VECTOR_HEADER Structure for packet sending
        /// </summary>
        /// <returns></returns>
        public RDPUDP_ACK_VECTOR_HEADER CreateAckVectorHeader()
        {
            RDPUDP_ACK_VECTOR_HEADER ackVectorHeader = new RDPUDP_ACK_VECTOR_HEADER();

            if (inPacketDic.Count == 0)
            {
                // Not receive any source packet
                ackVectorHeader.uAckVectorSize   = 0;
                ackVectorHeader.AckVectorElement = null;
                ackVectorHeader.Padding          = null;
            }
            else
            {
                lock (inPacketDic)
                {
                    // Generate an ACK header.
                    List <AckVector>     ackVectorElements = new List <AckVector>();
                    VECTOR_ELEMENT_STATE currentState      = inPacketDic.ContainsKey(InSnAckOfAcksSeqNum) ? VECTOR_ELEMENT_STATE.DATAGRAM_RECEIVED : VECTOR_ELEMENT_STATE.DATAGRAM_NOT_YET_RECEIVED;
                    AckVector            ackVectorElement  = new AckVector();
                    ackVectorElement.State  = currentState;
                    ackVectorElement.Length = 0;

                    // RLE encoding.
                    for (uint i = InSnAckOfAcksSeqNum + 1; i <= SnSourceAck; i++)
                    {
                        currentState = inPacketDic.ContainsKey(i) ? VECTOR_ELEMENT_STATE.DATAGRAM_RECEIVED : VECTOR_ELEMENT_STATE.DATAGRAM_NOT_YET_RECEIVED;

                        // 0x40 is the max length of state length, of which I believe sould be indicate from soket config or types config not hard code here.
                        if (currentState != ackVectorElement.State || ackVectorElement.Length >= 0x40)
                        {
                            // If current state differs from last state, assign a new ack vector.
                            ackVectorElements.Add(ackVectorElement);
                            ackVectorElement        = new AckVector();
                            ackVectorElement.State  = currentState;
                            ackVectorElement.Length = 0;
                        }
                        else
                        {
                            // Else count++.
                            ackVectorElement.Length++;
                        }
                    }
                    ackVectorElements.Add(ackVectorElement);
                    ackVectorHeader.uAckVectorSize   = (ushort)ackVectorElements.Count;
                    ackVectorHeader.AckVectorElement = ackVectorElements.ToArray();

                    // ACK Vector created for all received packet, set number of received packets for ACK to 0
                    sourceNumNotAcked = 0;
                }
            }

            return(ackVectorHeader);
        }
        public override bool Decode(PduMarshaler marshaler)
        {
            try
            {
                fecHeader.snSourceAck = marshaler.ReadUInt32();
                fecHeader.uReceiveWindowSize = marshaler.ReadUInt16();
                fecHeader.uFlags = (RDPUDP_FLAG)marshaler.ReadUInt16();

                if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN))
                {
                    RDPUDP_SYNDATA_PAYLOAD synData = new RDPUDP_SYNDATA_PAYLOAD();
                    synData.snInitialSequenceNumber = marshaler.ReadUInt32();
                    synData.uUpStreamMtu = marshaler.ReadUInt16();
                    synData.uDownStreamMtu = marshaler.ReadUInt16();
                    // This datagram MUST be zero-padded to increase the size of this datagram to 1232 bytes.

                    if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_CORRELATION_ID))
                    {
                        RDPUDP_CORRELATION_ID_PAYLOAD correlationId = new RDPUDP_CORRELATION_ID_PAYLOAD();
                        correlationId.uCorrelationId = marshaler.ReadBytes(16);
                        this.CorrelationId = correlationId;
                        correlationId.uReserved = marshaler.ReadBytes(16);
                    }

                    this.padding = marshaler.ReadToEnd();
                    this.SynData = synData;
                    return true;
                }

                if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK))
                {
                    // ACK.
                    RDPUDP_ACK_VECTOR_HEADER ackVector = new RDPUDP_ACK_VECTOR_HEADER();
                    ackVector.uAckVectorSize = marshaler.ReadUInt16();
                    ackVector.AckVectorElement = new AckVector[ackVector.uAckVectorSize];

                    List<byte> ackVecElementList = new List<byte>(marshaler.ReadBytes(ackVector.AckVectorElement.Length));
                    ackVecElementList.Reverse();

                    for (int i = 0; i < ackVector.AckVectorElement.Length; i++)
                    {
                        byte vecByte = ackVecElementList[i];
                        ackVector.AckVectorElement[i].Length = (byte)(0x3F & vecByte);
                        ackVector.AckVectorElement[i].State = (VECTOR_ELEMENT_STATE)(vecByte >> 6);
                    }

                    this.ackVectorHeader = ackVector;

                    // Padding (variable): A variable-sized array, of length zero or more,
                    // such that this structure ends on a DWORD ([MS-DTYP] section 2.2.9) boundary.
                    int padLen = 4 - (2 + ackVector.AckVectorElement.Length) % 4;
                    if (padLen > 0 && padLen != 4)
                    {
                        this.padding = marshaler.ReadBytes(padLen);
                    }

                    // Ack of Acks.
                    if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK_OF_ACKS))
                    {
                        RDPUDP_ACK_OF_ACKVECTOR_HEADER aoaHeader = new RDPUDP_ACK_OF_ACKVECTOR_HEADER();
                        aoaHeader.snAckOfAcksSeqNum = marshaler.ReadUInt32();
                        this.ackOfAckVector = aoaHeader;
                    }
                }

                if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_DATA))
                {
                    if (!fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_FEC))
                    {
                        // Source Data.
                        RDPUDP_SOURCE_PAYLOAD_HEADER srcHeader = new RDPUDP_SOURCE_PAYLOAD_HEADER();
                        srcHeader.snCoded = marshaler.ReadUInt32();
                        srcHeader.snSourceStart = marshaler.ReadUInt32();
                        this.sourceHeader = srcHeader;
                    }
                    else
                    {
                        // FEC Data.
                        RDPUDP_FEC_PAYLOAD_HEADER fecDataHeader = new RDPUDP_FEC_PAYLOAD_HEADER();
                        fecDataHeader.snCoded =  marshaler.ReadUInt32();
                        fecDataHeader.snSourceStart = marshaler.ReadUInt32();
                        fecDataHeader.uRange = marshaler.ReadByte();
                        fecDataHeader.uFecIndex = marshaler.ReadByte();
                        fecDataHeader.uPadding = marshaler.ReadUInt16();
                        this.fecPayloadHeader = fecDataHeader;
                    }

                    this.payload = marshaler.ReadToEnd();
                }

                return true;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// Create RDPUDP_ACK_VECTOR_HEADER Structure for packet sending
        /// </summary>
        /// <returns></returns>
        public RDPUDP_ACK_VECTOR_HEADER CreateAckVectorHeader()
        {
            RDPUDP_ACK_VECTOR_HEADER ackVectorHeader = new RDPUDP_ACK_VECTOR_HEADER();
            if (inPacketDic.Count == 0)
            {
                // Not receive any source packet
                ackVectorHeader.uAckVectorSize = 0;
                ackVectorHeader.AckVectorElement = null;
                ackVectorHeader.Padding = null;
            }
            else
            {
                lock (inPacketDic)
                {
                    // Generate an ACK header.
                    List<AckVector> ackVectorElements = new List<AckVector>();
                    VECTOR_ELEMENT_STATE currentState = inPacketDic.ContainsKey(InSnAckOfAcksSeqNum) ? VECTOR_ELEMENT_STATE.DATAGRAM_RECEIVED : VECTOR_ELEMENT_STATE.DATAGRAM_NOT_YET_RECEIVED;
                    AckVector ackVectorElement = new AckVector();
                    ackVectorElement.State = currentState;
                    ackVectorElement.Length = 0;

                    // RLE encoding.
                    for (uint i = InSnAckOfAcksSeqNum + 1; i <= SnSourceAck; i++)
                    {
                        currentState = inPacketDic.ContainsKey(i) ? VECTOR_ELEMENT_STATE.DATAGRAM_RECEIVED : VECTOR_ELEMENT_STATE.DATAGRAM_NOT_YET_RECEIVED;

                        // 0x40 is the max length of state length, of which I believe sould be indicate from soket config or types config not hard code here.
                        if (currentState != ackVectorElement.State || ackVectorElement.Length >= 0x40)
                        {
                            // If current state differs from last state, assign a new ack vector.
                            ackVectorElements.Add(ackVectorElement);
                            ackVectorElement = new AckVector();
                            ackVectorElement.State = currentState;
                            ackVectorElement.Length = 0;
                        }
                        else
                        {
                            // Else count++.
                            ackVectorElement.Length++;
                        }
                    }
                    ackVectorElements.Add(ackVectorElement);
                    ackVectorHeader.uAckVectorSize = (ushort)ackVectorElements.Count;
                    ackVectorHeader.AckVectorElement = ackVectorElements.ToArray();

                    // ACK Vector created for all received packet, set number of received packets for ACK to 0
                    sourceNumNotAcked = 0;
                }
            }

            return ackVectorHeader;
        }
        public override bool Decode(PduMarshaler marshaler)
        {
            try
            {
                fecHeader.snSourceAck        = marshaler.ReadUInt32();
                fecHeader.uReceiveWindowSize = marshaler.ReadUInt16();
                fecHeader.uFlags             = (RDPUDP_FLAG)marshaler.ReadUInt16();

                if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYN))
                {
                    RDPUDP_SYNDATA_PAYLOAD synData = new RDPUDP_SYNDATA_PAYLOAD();
                    synData.snInitialSequenceNumber = marshaler.ReadUInt32();
                    synData.uUpStreamMtu            = marshaler.ReadUInt16();
                    synData.uDownStreamMtu          = marshaler.ReadUInt16();
                    // This datagram MUST be zero-padded to increase the size of this datagram to 1232 bytes.

                    if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_CORRELATION_ID))
                    {
                        RDPUDP_CORRELATION_ID_PAYLOAD correlationId = new RDPUDP_CORRELATION_ID_PAYLOAD();
                        correlationId.uCorrelationId = marshaler.ReadBytes(16);
                        this.CorrelationId           = correlationId;
                        correlationId.uReserved      = marshaler.ReadBytes(16);
                    }

                    if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_SYNEX))
                    {
                        RDPUDP_SYNDATAEX_PAYLOAD synDataEx = new RDPUDP_SYNDATAEX_PAYLOAD();
                        synDataEx.uSynExFlags = (uSynExFlags_Values)marshaler.ReadUInt16();
                        synDataEx.uUdpVer     = (uUdpVer_Values)marshaler.ReadUInt16();
                        this.SynDataEx        = synDataEx;
                    }

                    this.padding = marshaler.ReadToEnd();
                    this.SynData = synData;
                    return(true);
                }


                if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK))
                {
                    // ACK.
                    RDPUDP_ACK_VECTOR_HEADER ackVector = new RDPUDP_ACK_VECTOR_HEADER();
                    ackVector.uAckVectorSize   = marshaler.ReadUInt16();
                    ackVector.AckVectorElement = new AckVector[ackVector.uAckVectorSize];

                    List <byte> ackVecElementList = new List <byte>(marshaler.ReadBytes(ackVector.AckVectorElement.Length));
                    ackVecElementList.Reverse();

                    for (int i = 0; i < ackVector.AckVectorElement.Length; i++)
                    {
                        byte vecByte = ackVecElementList[i];
                        ackVector.AckVectorElement[i].Length = (byte)(0x3F & vecByte);
                        ackVector.AckVectorElement[i].State  = (VECTOR_ELEMENT_STATE)(vecByte >> 6);
                    }

                    this.ackVectorHeader = ackVector;

                    // Padding (variable): A variable-sized array, of length zero or more,
                    // such that this structure ends on a DWORD ([MS-DTYP] section 2.2.9) boundary.
                    int padLen = 4 - (2 + ackVector.AckVectorElement.Length) % 4;
                    if (padLen > 0 && padLen != 4)
                    {
                        this.padding = marshaler.ReadBytes(padLen);
                    }


                    // Ack of Acks.
                    if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_ACK_OF_ACKS))
                    {
                        RDPUDP_ACK_OF_ACKVECTOR_HEADER aoaHeader = new RDPUDP_ACK_OF_ACKVECTOR_HEADER();
                        aoaHeader.snAckOfAcksSeqNum = marshaler.ReadUInt32();
                        this.ackOfAckVector         = aoaHeader;
                    }
                }

                if (fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_DATA))
                {
                    if (!fecHeader.uFlags.HasFlag(RDPUDP_FLAG.RDPUDP_FLAG_FEC))
                    {
                        // Source Data.
                        RDPUDP_SOURCE_PAYLOAD_HEADER srcHeader = new RDPUDP_SOURCE_PAYLOAD_HEADER();
                        srcHeader.snCoded       = marshaler.ReadUInt32();
                        srcHeader.snSourceStart = marshaler.ReadUInt32();
                        this.sourceHeader       = srcHeader;
                    }
                    else
                    {
                        // FEC Data.
                        RDPUDP_FEC_PAYLOAD_HEADER fecDataHeader = new RDPUDP_FEC_PAYLOAD_HEADER();
                        fecDataHeader.snCoded       = marshaler.ReadUInt32();
                        fecDataHeader.snSourceStart = marshaler.ReadUInt32();
                        fecDataHeader.uRange        = marshaler.ReadByte();
                        fecDataHeader.uFecIndex     = marshaler.ReadByte();
                        fecDataHeader.uPadding      = marshaler.ReadUInt16();
                        this.fecPayloadHeader       = fecDataHeader;
                    }

                    this.payload = marshaler.ReadToEnd();
                }

                return(true);
            }
            catch
            {
                return(false);
            }
        }
        public void S2_DataTransfer_RetransmitTest_ClientRetransmit()
        {
            // Record the sequenceNumber of the lost source packet.
            uint sequenceNumberForLossPacket = 0;
            ushort receiveWindowSize = 0;

            Site.Log.Add(LogEntryKind.Debug, "Establishing RDP connection ...");
            StartRDPConnection();

            this.TestSite.Log.Add(LogEntryKind.Comment, "Create a reliable UDP connection.");
            this.EstablishUDPConnection(TransportMode.Reliable, waitTime, true);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Send the first RDPEUDP Source packet, but not acknowledge the receipt of the first source packet from client.");
            RdpeudpPacket packet = this.GetFirstValidUdpPacket(TransportMode.Reliable);

            #region Change packet.ackVectorHeader To Not Acknowledge The Receipt

            RDPUDP_ACK_VECTOR_HEADER ackVectorHeader = new RDPUDP_ACK_VECTOR_HEADER();
            ackVectorHeader.AckVectorElement = null;
            ackVectorHeader.uAckVectorSize = 0;
            packet.ackVectorHeader = ackVectorHeader;
            sequenceNumberForLossPacket = packet.fecHeader.snSourceAck;
            receiveWindowSize = packet.fecHeader.uReceiveWindowSize;
            packet.fecHeader.snSourceAck--;

            #endregion Change packet.ackVectorHeader To Not Acknowledge The Receipt

            this.SendPacket(TransportMode.Reliable, packet);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Wait for 200 ms so as to fire the retransmit timer.");
            Thread.Sleep(this.RetransmitTimer);

            this.TestSite.Log.Add(LogEntryKind.Comment, "Wait for the client to resend the lost packet.");
            RdpeudpPacket receivedPacket = this.WaitForSourcePacket(TransportMode.Reliable, waitTime, sequenceNumberForLossPacket);
            Site.Assert.IsNotNull(receivedPacket, "Client should resend the packet if not receiving an ACK for a specified time.");
        }