Пример #1
0
        /// <summary>
        /// Generate UInt16 corresponding to header.
        /// </summary>
        /// <param name="header">header to be encoded</param>
        /// <returns>UInt16 representation of the header</returns>
        static public UInt16 Encode(FragmentHeader header)
        {
            UInt16 mask;
            UInt16 value = 0;
            UInt16 utype = (UInt16)header.Type;

            mask   = 0x0001; // 1 bit for type
            value |= (UInt16)((utype & mask) << (byte)FragmentHeaderField.Type);
            value |= (UInt16)(header.MessageSeqNumber << (byte)FragmentHeaderField.MessageNumber);
            mask   = 0x003F; // 6 bits for fragmentSeqNumber
            value |= (UInt16)((header.FragmentSeqNumber & mask) << (byte)FragmentHeaderField.FragmentSeqNumber);
            if (header.IsAckRequired)
            {
                mask   = 0x0001;
                mask   = (UInt16)(mask << (byte)FragmentHeaderField.RequireAck);
                value |= mask;
            }

            return(value);
        }
Пример #2
0
        /// <summary>
        /// Create a frame containing a DATA fragment
        /// </summary>
        /// <param name="messageSeqNumber">message sequence number</param>
        /// <param name="fragmentSeqNumber">fragment sequence number</param>
        /// <param name="isBroadcast">true if fragment is broadcasted</param>
        /// <param name="requireAck">true if an acknowledgment is required</param>
        /// <param name="pduSize">max size for the sublayer payload</param>
        /// <param name="reservedTail">max size for the sublayer tail</param>
        /// <param name="reservedHead">max size for the sublayer header</param>
        /// <param name="nbFragments">number of DATA fragments in the message</param>
        /// <param name="fragmentIndex">index of the DATA fragment</param>
        /// <param name="payloadData">payload</param>
        /// <param name="indexPayloadData">start index in the payload </param>
        /// <param name="nbBytes">number of bytes in the payload</param>
        /// <returns>the generated frame</returns>
        public static Frame CreateDataFrame(byte messageSeqNumber, byte fragmentSeqNumber, bool isBroadcast, bool requireAck,
                                            int pduSize, int reservedTail, int reservedHead, byte nbFragments, byte fragmentIndex, Frame payloadData, int indexPayloadData, int nbBytes)
        {
            if (pduSize < 2 + 2 + nbBytes)
            {
                throw new ArgumentException("pdu size is too small", "pduSize");
            }
            FragmentHeader header = new FragmentHeader(FragmentType.DATA, messageSeqNumber, requireAck, fragmentSeqNumber);

            Frame frame = Frame.GetFrame(reservedHead + reservedTail + 2 + 2 + nbBytes);

            frame.ReserveHeader(reservedHead);
            UInt16 serializedHdr = FragmentHeader.Encode(header);

            frame.AllocBack(4);
            frame.Write(0, serializedHdr);
            frame.Write(2, nbFragments);
            frame.Write(3, fragmentIndex);
            frame.AppendToBack(payloadData, indexPayloadData, nbBytes);
            return(frame);
        }
Пример #3
0
        /// <summary>
        /// Create a frame containing an ACK fragment
        /// </summary>
        /// <param name="messageSeqNumber">message sequence number</param>
        /// <param name="fragmentSeqNumber">fragment sequence number</param>
        /// <param name="pduSize">max size for the sublayer payload</param>
        /// <param name="reservedTail">max size for the sublayer tail</param>
        /// <param name="reservedHead">max size for the sublayer header</param>
        /// <param name="lastFragmentSeqNumberReceived">last fragment sequence number received by the receiver</param>
        /// <param name="fragmentMissingTable">table of missing fragments</param>
        /// <returns>the generated frame</returns>
        public static Frame CreateAckFragmentFrame(byte messageSeqNumber, byte fragmentSeqNumber, int pduSize, int reservedTail, int reservedHead, byte lastFragmentSeqNumberReceived, BitArray fragmentMissingTable)
        {
            byte[] byteArray = BitArray.ToByteArray(fragmentMissingTable);
            if (pduSize < 2 /* header */ + 1 /*last frag nb rec. */ + byteArray.Length + 1 /* size bit array */)
            {
                throw new ArgumentException("pdu size is too small", "pduSize");
            }
            FragmentHeader header = new FragmentHeader(FragmentType.ACK, messageSeqNumber, false, fragmentSeqNumber);

            Frame frame = Frame.GetFrame(reservedHead + reservedTail + 2 + 1 + byteArray.Length + 1);

            frame.ReserveHeader(reservedHead);
            UInt16 serializedHdr = FragmentHeader.Encode(header);

            frame.AllocBack(4);
            frame.Write(0, serializedHdr);
            frame.Write(2, lastFragmentSeqNumberReceived);
            frame.Write(3, (byte)fragmentMissingTable.Length);
            frame.AppendToBack(byteArray, 0, byteArray.Length);
            return(frame);
        }
Пример #4
0
        /// <summary>
        /// Generate UInt16 corresponding to header.
        /// </summary>
        /// <param name="header">header to be encoded</param>
        /// <returns>UInt16 representation of the header</returns>
        static public UInt16 Encode(FragmentHeader header)
        {
            UInt16 mask;
            UInt16 value = 0;
            UInt16 utype = (UInt16)header.Type;
            mask = 0x0001; // 1 bit for type
            value |= (UInt16)((utype & mask) << (byte)FragmentHeaderField.Type);
            value |= (UInt16)(header.MessageSeqNumber << (byte)FragmentHeaderField.MessageNumber);
            mask = 0x003F; // 6 bits for fragmentSeqNumber
            value |= (UInt16)((header.FragmentSeqNumber & mask) << (byte)FragmentHeaderField.FragmentSeqNumber);
            if (header.IsAckRequired)
            {
                mask = 0x0001;
                mask = (UInt16)(mask << (byte)FragmentHeaderField.RequireAck);
                value |= mask;
            }

            return value;
        }
Пример #5
0
        /// <summary>
        /// Create a frame containing a DATA fragment
        /// </summary>
        /// <param name="messageSeqNumber">message sequence number</param>
        /// <param name="fragmentSeqNumber">fragment sequence number</param>
        /// <param name="isBroadcast">true if fragment is broadcasted</param>
        /// <param name="requireAck">true if an acknowledgment is required</param>
        /// <param name="pduSize">max size for the sublayer payload</param>
        /// <param name="reservedTail">max size for the sublayer tail</param>
        /// <param name="reservedHead">max size for the sublayer header</param>
        /// <param name="nbFragments">number of DATA fragments in the message</param>
        /// <param name="fragmentIndex">index of the DATA fragment</param>
        /// <param name="payloadData">payload</param>
        /// <param name="indexPayloadData">start index in the payload </param>
        /// <param name="nbBytes">number of bytes in the payload</param>
        /// <returns>the generated frame</returns>
        public static Frame CreateDataFrame(byte messageSeqNumber, byte fragmentSeqNumber, bool isBroadcast, bool requireAck,
            int pduSize, int reservedTail, int reservedHead, byte nbFragments, byte fragmentIndex, Frame payloadData, int indexPayloadData, int nbBytes)
        {
            if (pduSize < 2 + 2 + nbBytes)
                throw new ArgumentException("pdu size is too small", "pduSize");
            FragmentHeader header = new FragmentHeader(FragmentType.DATA, messageSeqNumber, requireAck, fragmentSeqNumber);

            Frame frame = Frame.GetFrame(reservedHead + reservedTail + 2 + 2 + nbBytes);
            frame.ReserveHeader(reservedHead);
            UInt16 serializedHdr = FragmentHeader.Encode(header);
            frame.AllocBack(4);
            frame.Write(0, serializedHdr);
            frame.Write(2, nbFragments);
            frame.Write(3, fragmentIndex);
            frame.AppendToBack(payloadData, indexPayloadData, nbBytes);
            return frame;
        }
Пример #6
0
        /// <summary>
        /// Create a frame containing an ACK fragment
        /// </summary>
        /// <param name="messageSeqNumber">message sequence number</param>
        /// <param name="fragmentSeqNumber">fragment sequence number</param>
        /// <param name="pduSize">max size for the sublayer payload</param>
        /// <param name="reservedTail">max size for the sublayer tail</param>
        /// <param name="reservedHead">max size for the sublayer header</param>
        /// <param name="lastFragmentSeqNumberReceived">last fragment sequence number received by the receiver</param>
        /// <param name="fragmentMissingTable">table of missing fragments</param>
        /// <returns>the generated frame</returns>
        public static Frame CreateAckFragmentFrame(byte messageSeqNumber, byte fragmentSeqNumber, int pduSize, int reservedTail, int reservedHead, byte lastFragmentSeqNumberReceived, BitArray fragmentMissingTable)
        {
            byte[] byteArray = BitArray.ToByteArray(fragmentMissingTable);
            if (pduSize < 2 /* header */ + 1 /*last frag nb rec. */  + byteArray.Length + 1 /* size bit array */)
                throw new ArgumentException("pdu size is too small", "pduSize");
            FragmentHeader header = new FragmentHeader(FragmentType.ACK, messageSeqNumber, false, fragmentSeqNumber);

            Frame frame = Frame.GetFrame(reservedHead + reservedTail + 2 + 1 + byteArray.Length + 1);
            frame.ReserveHeader(reservedHead);
            UInt16 serializedHdr = FragmentHeader.Encode(header);
            frame.AllocBack(4);
            frame.Write(0, serializedHdr);
            frame.Write(2, lastFragmentSeqNumberReceived);
            frame.Write(3, (byte)fragmentMissingTable.Length);
            frame.AppendToBack(byteArray, 0, byteArray.Length);
            return frame;
        }
        internal override void HandleReceivedFragment(FragmentHeader header, ref Frame payload)
        {
            if (header.FragmentSeqNumber == _lastFragmentSeqNumberReceived)
            {
#if PRINTALL
                Trace.Print("Already received this fragment. Drop.");
#endif
                Frame.Release(ref payload);
                return;
            }

            _lastFragmentSeqNumberReceived = header.FragmentSeqNumber;

            if ((header.Type != FragmentType.ACK) || (header.MessageSeqNumber != _messageSeqNumber))
            {
                Frame.Release(ref payload);
                return;
            }

            FragmentationMessageTerminatedEventArgs messageTerminatedHandlerArgs = null;
            bool sendData = false;

            lock (_lock)
            {
                if (_currentState == FragmentationMessageState.Disposed)
                {
                    Frame.Release(ref payload);
                    return;
                }

                bool timerWasEnabled = _timerEnabled;
                if (_timerEnabled)
                {
                    _timer.UnregisterItem(this);
                    _timerEnabled = false;
                }

                _nbTimeoutWithoutAck = 0;
                if (header.Type == FragmentType.ACK)
                {
#if PRINTALL
                    Trace.Print("Received ACK for message " + header.MessageSeqNumber + " sduHandle=" + _sduHandle);
#endif
                    _nbFragmentsSentWithoutAck = 0;
                    BitArray fragmentMissingTable;
                    byte     lastFragmentSeqNumberReceivedByReceived = 255;
                    try
                    {
                        Fragment.DecodeAckPayload(ref payload, out lastFragmentSeqNumberReceivedByReceived, out fragmentMissingTable);
                        Frame.Release(ref payload);
                        if (fragmentMissingTable.Length == _successfullyTransmittedFragments.Length)
                        {
                            BitArray fragmentReceived = fragmentMissingTable.Clone();
                            fragmentReceived.Not();
#if PRINTALL
                            string msg = "";
                            for (int i = 0; i < fragmentReceived.Length; i++)
                            {
                                if (fragmentReceived.Get(i))
                                {
                                    msg += i + ",";
                                }
                            }

                            Trace.Print("received so far: " + msg);
#endif
                            _successfullyTransmittedFragments.Or(fragmentReceived);
                            if (_successfullyTransmittedFragments.CheckAllSet(true))
                            {
                                _allFragmentTransmitted = true;
                                _currentState           = FragmentationMessageState.Final;
                            }

                            // now check if we received  ACK for the last fragment that we sent.
                            if (lastFragmentSeqNumberReceivedByReceived == _lastFragmentSeqNumberSent)
                            {
                                long roundTripTime = (DateTime.Now.Ticks - _timeLastFragmentSent.Ticks) / TimeSpan.TicksPerMillisecond;
                                if (2 * roundTripTime <= (long)uint.MaxValue)
                                {
                                    _timeoutForResending = (uint)(2 * roundTripTime);
                                }

                                _maxFragmentsBeforeAck++;
                            }

                            _lastFragmentSent.SetAll(false);
                        }
                    }
                    catch (ArgumentException)
                    {
                        // could not decode payload.
                        if (timerWasEnabled)
                        {
                            _timer.RegisterItem(_timeoutTicks, this);
                            _timerEnabled = true;
                        }

                        Frame.Release(ref payload);
                        return;
                    }

                    if (_allFragmentTransmitted)
                    {
                        _currentState = FragmentationMessageState.Final;
                        messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, Status.Success);
                    }
                    else
                    {
                        sendData = true;
                    }
                }
                else
                {
#if DEBUG
                    Trace.Print("Received bad fragment type for message " + header.MessageSeqNumber + " sdhHandle=" + _sduHandle);
#endif
                    Frame.Release(ref payload);
                    if (timerWasEnabled)
                    {
                        _timer.RegisterItem(_timeoutTicks, this);
                        _timerEnabled = true;
                    }
                }
            }

            // release the lock before calling OnFragmentationMessageFinalState since upper layer handler is called.
            if (messageTerminatedHandlerArgs != null)
            {
                OnFragmentationMessageTerminated(messageTerminatedHandlerArgs);
            }
            else if (sendData)
            {
                SendNextDataFragment(false);
            }
        }
        internal override void HandleReceivedFragment(FragmentHeader header, ref Frame payload)
        {
            if (header.FragmentSeqNumber == _lastFragmentSeqNumberReceived)
            {
#if DEBUG
                Trace.Print("Already received this fragment. Drop.");
#endif

                Frame.Release(ref payload);
                return;
            }

            _lastFragmentSeqNumberReceived = header.FragmentSeqNumber;

            if ((header.Type != FragmentType.DATA) || (payload.LengthDataUsed < 2) || (_messageSeqNumber != header.MessageSeqNumber))
            {
                Frame.Release(ref payload);
                return;
            }

            byte  nbFragments;
            byte  fragmentIndex;
            Frame data;
            try
            {
                Fragment.DecodeDataPayload(ref payload, out nbFragments, out fragmentIndex, out data);
            }
            catch (ArgumentException)
            {
                Frame.Release(ref payload);
                return;
            }

#if PRINTALL
            Trace.Print("Receiving part  " + fragmentIndex + "/" + nbFragments + " of packet " + _messageSeqNumber);
#endif

            FragmentationMessageTerminatedEventArgs messageTerminatedHandlerArgs = null;
            bool sendAck = false;
            lock (_lock)
            {
                if (_currentState == FragmentationMessageState.Disposed)
                {
                    Frame.Release(ref data);
                    return;
                }

                if (_timerEnabled)
                {
                    _timer.UnregisterItem(this);
                    _timerEnabled = false;
                }

                if ((_fragmentMissingTable != null) && (nbFragments != _fragmentMissingTable.Length))
                {
                    // mismatch between messages: no the same number of fragments
                    Frame.Release(ref data);
                    return;
                }

                FragmentationMessageState oldState = _currentState;
                if (_sduCompleted)
                {
                    Frame.Release(ref data);
                    if (header.IsAckRequired)
                    {
                        // resend acknowlegment
                        sendAck = true;
                    }
                    else
                    {
                        // leave the state unchanged
                        return;
                    }
                }
                else
                {
                    switch (_currentState)
                    {
                    case FragmentationMessageState.Initial:
                    case FragmentationMessageState.WaitingFragments:
                    case FragmentationMessageState.WaitingSentStatus:
                    case FragmentationMessageState.WaitingTimeoutBeforeResending:
                        if (_currentState == FragmentationMessageState.Initial)
                        {
                            // first fragment received.
                            _fragmentData         = new Frame[nbFragments];
                            _fragmentMissingTable = new BitArray(nbFragments, true);
                        }

                        _fragmentMissingTable.Set(fragmentIndex, false);
                        if (_fragmentData[fragmentIndex] == null)
                        {
                            _fragmentData[fragmentIndex] = data;
                        }
                        else
                        {
                            Frame.Release(ref data);
                        }

                        _sduCompleted = _fragmentMissingTable.CheckAllSet(false);
                        if (header.IsAckRequired)
                        {
                            sendAck = true;
                        }
                        else
                        {
                            _currentState = FragmentationMessageState.WaitingFragments;
                        }

                        if (_sduCompleted)
                        {
                            _currentState = FragmentationMessageState.Final;
                            messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, Status.Success);
                        }
                        break;

                    case FragmentationMessageState.WaitingAck:
                        Frame.Release(ref data);
                        throw new System.InvalidOperationException("Bad state.");

                    case FragmentationMessageState.Disposed:
                    case FragmentationMessageState.Final:
                    case FragmentationMessageState.Unknown:
                    default:
                        Frame.Release(ref data);
                        break;
                    }
                }
            }

            if (sendAck)
            {
                SendAcknowledgement();
            }

            if (messageTerminatedHandlerArgs != null)
            {
                OnFragmentationMessageTerminated(messageTerminatedHandlerArgs);
            }
        }
 /// <summary>
 /// Switch to next state after receiving a new segment
 /// </summary>
 /// <param name="segment">The segment</param>
 internal abstract void HandleReceivedFragment(FragmentHeader header, ref Frame payload);
Пример #10
0
        public void HandleLowerLayerDataIndication(object sender, ushort originatorShortAddr, ushort targetShortAddr, Frame sdu)
        {
            FragmentationMessage fragMsg = null;
            FragmentHeader       header;

            lock (_lock)
            {
                if ((!_started) || (sdu.LengthDataUsed < 2))
                {
                    Frame.Release(ref sdu);
                    return;
                }

                // extract fragment header.
                header = FragmentHeader.Decode(sdu.ReadUInt16(0));
                sdu.DeleteFromFront(2);
                FragmentationMessageAssociationSet associations;
                switch (header.Type)
                {
                case FragmentType.DATA:
                    associations = _inboundAssociations;
                    if (associations == null)
                    {
                        Frame.Release(ref sdu);
                        return;
                    }

                    fragMsg = (InboundFragmentationMessage)associations.GetFragmentationMessage(originatorShortAddr, targetShortAddr);
                    if (fragMsg != null)
                    {
                        // there is already one message with this peer. Check freshness.
                        if (fragMsg.MessageNumber != header.MessageSeqNumber)
                        {
                            int sqnOld = (int)fragMsg.MessageNumber;
                            int sqnNew = (int)header.MessageSeqNumber;
                            int diff   = (sqnNew > sqnOld) ? sqnNew - sqnOld : sqnNew - sqnOld + 256;
                            if ((header.MessageSeqNumber == 0) || (diff < 128))
                            {
                                // data received is most recent.
                                fragMsg.Dispose();
                                fragMsg = null;
                            }
                            else
                            {
                                // data received is old stuff.
                                Frame.Release(ref sdu);
                                return;
                            }
                        }
                    }

                    if (fragMsg == null)
                    {
                        // new message must be started
                        fragMsg = new InboundFragmentationMessage(originatorShortAddr, targetShortAddr,
                                                                  header.MessageSeqNumber, _lowerLayerDataRequest, _lowerMtu, _lowerHead, _lowerTail, _timer);
                        fragMsg.FragmentationMessageTerminated += this.HandleFragmentationMessageTerminated;
                        associations.SetFragmentationMessage(originatorShortAddr, targetShortAddr, fragMsg);
                    }
                    break;

                case FragmentType.ACK:
                    associations = _outboundAssociations;
                    if (associations == null)
                    {
                        Frame.Release(ref sdu);
                        return;
                    }

                    fragMsg = (OutboundFragmentationMessage)associations.GetFragmentationMessage(targetShortAddr, originatorShortAddr);
                    if ((fragMsg == null) || (fragMsg.MessageNumber != header.MessageSeqNumber))
                    {
                        //no one waiting for this segment. Discard.
#if DEBUG
                        Trace.Print("No one waiting for this segment. Discard.");
#endif

                        Frame.Release(ref sdu);
                        return;
                    }
                    break;

                default:
                    break;
                }
            }

            // release the lock before calling method in FragmentMessage class
            if (fragMsg != null)
            {
                fragMsg.HandleReceivedFragment(header, ref sdu);
            }
        }
        internal override void HandleReceivedFragment(FragmentHeader header, ref Frame payload)
        {
            if (header.FragmentSeqNumber == _lastFragmentSeqNumberReceived)
            {
#if DEBUG
                Trace.Print("Already received this fragment. Drop.");
#endif

                Frame.Release(ref payload);
                return;
            }

            _lastFragmentSeqNumberReceived = header.FragmentSeqNumber;

            if ((header.Type != FragmentType.DATA) || (payload.LengthDataUsed < 2) || (_messageSeqNumber != header.MessageSeqNumber))
            {
                Frame.Release(ref payload);
                return;
            }

            byte nbFragments;
            byte fragmentIndex;
            Frame data;
            try
            {
                Fragment.DecodeDataPayload(ref payload, out nbFragments, out fragmentIndex, out data);
            }
            catch (ArgumentException)
            {
                Frame.Release(ref payload);
                return;
            }

#if PRINTALL
            Trace.Print("Receiving part  " + fragmentIndex + "/" + nbFragments + " of packet " + _messageSeqNumber);
#endif

            FragmentationMessageTerminatedEventArgs messageTerminatedHandlerArgs = null;
            bool sendAck = false;
            lock (_lock)
            {
                if (_currentState == FragmentationMessageState.Disposed)
                {
                    Frame.Release(ref data);
                    return;
                }

                if (_timerEnabled)
                {
                    _timer.UnregisterItem(this);
                    _timerEnabled = false;
                }

                if ((_fragmentMissingTable != null) && (nbFragments != _fragmentMissingTable.Length))
                {
                    // mismatch between messages: no the same number of fragments
                    Frame.Release(ref data);
                    return;
                }

                FragmentationMessageState oldState = _currentState;
                if (_sduCompleted)
                {
                    Frame.Release(ref data);
                    if (header.IsAckRequired)
                    {
                        // resend acknowlegment
                        sendAck = true;
                    }
                    else
                    {
                        // leave the state unchanged
                        return;
                    }
                }
                else
                {
                    switch (_currentState)
                    {
                        case FragmentationMessageState.Initial:
                        case FragmentationMessageState.WaitingFragments:
                        case FragmentationMessageState.WaitingSentStatus:
                        case FragmentationMessageState.WaitingTimeoutBeforeResending:
                            if (_currentState == FragmentationMessageState.Initial)
                            {
                                // first fragment received.
                                _fragmentData = new Frame[nbFragments];
                                _fragmentMissingTable = new BitArray(nbFragments, true);
                            }

                            _fragmentMissingTable.Set(fragmentIndex, false);
                            if (_fragmentData[fragmentIndex] == null)
                            {
                                _fragmentData[fragmentIndex] = data;
                            }
                            else
                            {
                                Frame.Release(ref data);
                            }

                            _sduCompleted = _fragmentMissingTable.CheckAllSet(false);
                            if (header.IsAckRequired)
                            {
                                sendAck = true;
                            }
                            else
                            {
                                _currentState = FragmentationMessageState.WaitingFragments;
                            }

                            if (_sduCompleted)
                            {
                                _currentState = FragmentationMessageState.Final;
                                messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, Status.Success);
                            }
                            break;
                        case FragmentationMessageState.WaitingAck:
                            Frame.Release(ref data);
                            throw new System.InvalidOperationException("Bad state.");
                        case FragmentationMessageState.Disposed:
                        case FragmentationMessageState.Final:
                        case FragmentationMessageState.Unknown:
                        default:
                            Frame.Release(ref data);
                            break;
                    }
                }
            }

            if (sendAck)
            {
                SendAcknowledgement();
            }

            if (messageTerminatedHandlerArgs != null)
            {
                OnFragmentationMessageTerminated(messageTerminatedHandlerArgs);
            }
        }
        internal override void HandleReceivedFragment(FragmentHeader header, ref Frame payload)
        {
            if (header.FragmentSeqNumber == _lastFragmentSeqNumberReceived)
            {
#if PRINTALL
                Trace.Print("Already received this fragment. Drop.");
#endif
                Frame.Release(ref payload);
                return;
            }

            _lastFragmentSeqNumberReceived = header.FragmentSeqNumber;

            if ((header.Type != FragmentType.ACK) || (header.MessageSeqNumber != _messageSeqNumber))
            {
                Frame.Release(ref payload);
                return;
            }

            FragmentationMessageTerminatedEventArgs messageTerminatedHandlerArgs = null;
            bool sendData = false;

            lock (_lock)
            {

                if (_currentState == FragmentationMessageState.Disposed)
                {
                    Frame.Release(ref payload);
                    return;
                }

                bool timerWasEnabled = _timerEnabled;
                if (_timerEnabled)
                {
                    _timer.UnregisterItem(this);
                    _timerEnabled = false;
                }

                _nbTimeoutWithoutAck = 0;
                if (header.Type == FragmentType.ACK)
                {
#if PRINTALL
                    Trace.Print("Received ACK for message " + header.MessageSeqNumber + " sduHandle=" + _sduHandle);
#endif
                    _nbFragmentsSentWithoutAck = 0;
                    BitArray fragmentMissingTable;
                    byte lastFragmentSeqNumberReceivedByReceived = 255;
                    try
                    {
                        Fragment.DecodeAckPayload(ref payload, out lastFragmentSeqNumberReceivedByReceived, out fragmentMissingTable);
                        Frame.Release(ref payload);
                        if (fragmentMissingTable.Length == _successfullyTransmittedFragments.Length)
                        {
                            BitArray fragmentReceived = fragmentMissingTable.Clone();
                            fragmentReceived.Not();
#if PRINTALL
                            string msg = "";
                            for (int i = 0; i < fragmentReceived.Length; i++)
                            {
                                if (fragmentReceived.Get(i))
                                {
                                    msg += i + ",";
                                }
                            }

                            Trace.Print("received so far: " + msg);
#endif
                            _successfullyTransmittedFragments.Or(fragmentReceived);
                            if (_successfullyTransmittedFragments.CheckAllSet(true))
                            {
                                _allFragmentTransmitted = true;
                                _currentState = FragmentationMessageState.Final;
                            }

                            // now check if we received  ACK for the last fragment that we sent.
                            if (lastFragmentSeqNumberReceivedByReceived == _lastFragmentSeqNumberSent)
                            {
                                long roundTripTime = (DateTime.Now.Ticks - _timeLastFragmentSent.Ticks) / TimeSpan.TicksPerMillisecond;
                                if (2 * roundTripTime <= (long)uint.MaxValue)
                                    _timeoutForResending = (uint)(2 * roundTripTime);

                                _maxFragmentsBeforeAck++;
                            }

                            _lastFragmentSent.SetAll(false);
                        }

                    }
                    catch (ArgumentException)
                    {
                        // could not decode payload.
                        if (timerWasEnabled)
                        {
                            _timer.RegisterItem(_timeoutTicks, this);
                            _timerEnabled = true;
                        }

                        Frame.Release(ref payload);
                        return;
                    }

                    if (_allFragmentTransmitted)
                    {
                        _currentState = FragmentationMessageState.Final;
                        messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, Status.Success);
                    }
                    else
                    {
                        sendData = true;
                    }

                }
                else
                {
#if DEBUG
                    Trace.Print("Received bad fragment type for message " + header.MessageSeqNumber + " sdhHandle=" + _sduHandle);
#endif
                    Frame.Release(ref payload);
                    if (timerWasEnabled)
                    {
                        _timer.RegisterItem(_timeoutTicks, this);
                        _timerEnabled = true;
                    }
                }
            }

            // release the lock before calling OnFragmentationMessageFinalState since upper layer handler is called.
            if (messageTerminatedHandlerArgs != null)
            {
                OnFragmentationMessageTerminated(messageTerminatedHandlerArgs);
            }
            else if (sendData)
            {
                SendNextDataFragment(false);
            }
        }
 /// <summary>
 /// Switch to next state after receiving a new segment
 /// </summary>
 /// <param name="segment">The segment</param>
 internal abstract void HandleReceivedFragment(FragmentHeader header, ref Frame payload);