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);
            }
        }