示例#1
0
        private void HandleFragmentationMessageTerminated(object sender, FragmentationMessageTerminatedEventArgs args)
        {
            if (sender is InboundFragmentationMessage)
            {
                if ((args.FinalState != FragmentationMessageState.Final) || (args.FinalStatus != Status.Success))
                {
                    // do nothing.
                    return;
                }

                InboundFragmentationMessage inMsg = sender as InboundFragmentationMessage;

                Frame receivedMessage = inMsg.RetrieveData();

                if (receivedMessage != null)
                {
                    DataIndicationHandler handler = _dataIndicationHandler;
                    if (handler != null)
                    {
                        handler.Invoke(this, inMsg.Source, inMsg.Destination, receivedMessage);
                    }
                    else
                    {
                        Frame.Release(ref receivedMessage);
                    }
                }
            }
            else if (sender is OutboundFragmentationMessage)
            {
                OutboundFragmentationMessage outMsg, newOutMsg;
                lock (_lock)
                {
                    outMsg = sender as OutboundFragmentationMessage;
                    ushort previousDestination = outMsg.Destination;
                    _transmissionCharacteristicStorage.UpdateTransmissionCharacteristic(outMsg.Destination, outMsg.TimeoutForResending,
                                                                                        outMsg.MaxFragmentsBeforeAck);
                    // remove active message from repository
                    _outboundAssociations.RemoveFragmentationMessage(outMsg);
                    // try to start new message (if possible)
                    DataRequestItem newItem;
                    newOutMsg = null;
                    if (_dataRequestQueueSet.Dequeue(previousDestination, out newItem))
                    {
                        newOutMsg = CreateNewOutboundMessage(newItem);
                    }
                }

                // after releasing the lock, call method in FragmentationMessage class.
                outMsg.NotifySender(args.FinalState, args.FinalStatus);
                outMsg.Dispose();

                if (newOutMsg != null)
                {
                    newOutMsg.SendNextDataFragment(true);
                }
            }
        }
        protected void OnFragmentationMessageTerminated(FragmentationMessageTerminatedEventArgs args)
        {
            FragmentationMessageTerminatedEventHandler handler = FragmentationMessageTerminated;

            if (!_notifcationOfFinalStateTransmitted && (handler != null))
            {
                _notifcationOfFinalStateTransmitted = true;
                handler(this, args);
            }
        }
        private void HandleFragmentationMessageTerminated(object sender, FragmentationMessageTerminatedEventArgs args)
        {
            if (sender is InboundFragmentationMessage)
            {
                if ((args.FinalState != FragmentationMessageState.Final) || (args.FinalStatus != Status.Success))
                {
                    // do nothing.
                    return;
                }

                InboundFragmentationMessage inMsg = sender as InboundFragmentationMessage;

                Frame receivedMessage = inMsg.RetrieveData();

                if (receivedMessage != null)
                {
                    DataIndicationHandler handler = _dataIndicationHandler;
                    if (handler != null)
                    {
                        handler.Invoke(this, inMsg.Source, inMsg.Destination, receivedMessage);
                    }
                    else
                    {
                        Frame.Release(ref receivedMessage);
                    }
                }

            }
            else if (sender is OutboundFragmentationMessage)
            {
                OutboundFragmentationMessage outMsg, newOutMsg;
                lock (_lock)
                {
                    outMsg = sender as OutboundFragmentationMessage;
                    ushort previousDestination = outMsg.Destination;
                    _transmissionCharacteristicStorage.UpdateTransmissionCharacteristic(outMsg.Destination, outMsg.TimeoutForResending,
                    outMsg.MaxFragmentsBeforeAck);
                    // remove active message from repository
                    _outboundAssociations.RemoveFragmentationMessage(outMsg);
                    // try to start new message (if possible)
                    DataRequestItem newItem;
                    newOutMsg = null;
                    if (_dataRequestQueueSet.Dequeue(previousDestination, out newItem))
                    {
                        newOutMsg = CreateNewOutboundMessage(newItem);
                    }

                }

                // after releasing the lock, call method in FragmentationMessage class.
                outMsg.NotifySender(args.FinalState, args.FinalStatus);
                outMsg.Dispose();

                if (newOutMsg != null) { newOutMsg.SendNextDataFragment(true); }
            }
        }
        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 HandleSendConfirmation(Object sender, byte sduHandle, Status status)
        {
            FragmentationMessageTerminatedEventArgs messageTerminatedHandlerArgs = null;
            bool sendData = false;

            lock (_lock)
            {
                if (_currentState == FragmentationMessageState.Disposed)
                {
                    return;
                }

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

                    _sendStatus = status;

                    switch (status)
                    {
                    case Status.Success:
                        if (_isBroadcast)
                        {
                            _successfullyTransmittedFragments.Or(_lastFragmentSent);
                            _allFragmentTransmitted = _successfullyTransmittedFragments.CheckAllSet(true);
                            if (_allFragmentTransmitted)
                            {
                                _currentState = FragmentationMessageState.Final;
                                messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, Status.Success);
                            }
                            else
                            {
                                sendData = true;
                            }
                        }
                        else
                        {
                            if (!_allFragmentTransmitted)
                            {
                                // check if continue sending fragment or wait for ACK.
                                if (_nbFragmentsSentWithoutAck >= _maxFragmentsBeforeAck)
                                {
                                    // wait for ack.
                                    _timeLastFragmentSent = DateTime.Now;
                                    _timeoutTicks         = _timeLastFragmentSent.Ticks + _timeoutForResending * TimeSpan.TicksPerMillisecond;
                                    _timerId      = _timer.RegisterItem(_timeoutTicks, this);
                                    _timerEnabled = true;
                                    _currentState = FragmentationMessageState.WaitingAck;
                                }
                                else
                                {
                                    _timeLastFragmentSent = DateTime.Now;
                                    sendData = true;
                                }
                            }
                            else
                            {
                                _currentState = FragmentationMessageState.Final;
                                messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, Status.Success);
                            }
                        }
                        break;

                    case Status.Timeout:
                    case Status.Busy:
#if DEBUG
                        Trace.Print("stack busy. wait for " + FragmentationMessage.c_timeoutWhenStackBusy + " ms.");
#endif
                        _timeoutTicks = DateTime.Now.Ticks + FragmentationMessage.c_timeoutWhenStackBusy * TimeSpan.TicksPerMillisecond;
                        _timerId      = _timer.RegisterItem(_timeoutTicks, this);
                        _timerEnabled = true;
                        _currentState = FragmentationMessageState.WaitingTimeoutBeforeResending;
                        break;

                    case Status.Error:
                    case Status.NoRoute:
                    case Status.NotRunning:
                    case Status.InvalidFrame:
                    default:
                        _currentState = FragmentationMessageState.SendingImpossible;
                        messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, _sendStatus);
                        break;
                    }
                }
            }

            // need to release the lock before calling OnFragmentationMessageFinalState since upper layer handler might be called.
            if (messageTerminatedHandlerArgs != null)
            {
                OnFragmentationMessageTerminated(messageTerminatedHandlerArgs);
            }
            else if (sendData)
            {
                SendNextDataFragment(false);
            }
        }
        override internal void HandleTimeout(Object sender, TimeoutEventArgs args)
        {
            FragmentationMessageTerminatedEventArgs messageTerminatedHandlerArgs = null;
            bool sendData = false;

#if PRINTALL
            Trace.Print("Timeout in outbound message!");
#endif

            lock (_lock)
            {
                if (!_timerEnabled)
                {
#if PRINTALL
                    Trace.Print("timer is not enabled. Do nothing.");
#endif
                    return;
                }

                _timerEnabled = false; // no need to unregister since automatically unregister when timeout is fired.
                if (_currentState == FragmentationMessageState.Disposed)
                {
                    return;
                }

                if (this != args.Message)
                {
                    throw new ArgumentException("timeout delivered with wrong message");
                }
                _nbTimeoutWithoutAck++;
                if (_nbTimeoutWithoutAck >= c_maxNbTimeoutWithoutNewMessage)
                {
                    _sendStatus   = Status.Timeout;
                    _currentState = FragmentationMessageState.SendingImpossible;

                    messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, _sendStatus);
                }
                else
                {
                    _nbFragmentsSentWithoutAck = 0;
                    _lastFragmentSent.SetAll(false);
                    _maxFragmentsBeforeAck /= 2;
                    if (_maxFragmentsBeforeAck == 0)
                    {
                        _maxFragmentsBeforeAck = 1;
                    }

                    _timeoutForResending = (2 * _timeoutForResending);
                    if (_timeoutForResending > c_maxTimeoutForResending)
                    {
                        _timeoutForResending = c_maxTimeoutForResending;
                    }

                    sendData = true;
                }
            }

            if (messageTerminatedHandlerArgs != null)
            {
                OnFragmentationMessageTerminated(messageTerminatedHandlerArgs);
            }
            else if (sendData)
            {
                SendNextDataFragment(true);
            }
        }
        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);
            }
        }
        internal override void HandleSendConfirmation(Object sender, byte sduHandle, Status status)
        {

            FragmentationMessageTerminatedEventArgs messageTerminatedHandlerArgs = null;
            bool sendData = false;

            lock (_lock)
            {
                if (_currentState == FragmentationMessageState.Disposed)
                {
                    return;
                }

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

                    _sendStatus = status;

                    switch (status)
                    {
                        case Status.Success:
                            if (_isBroadcast)
                            {
                                _successfullyTransmittedFragments.Or(_lastFragmentSent);
                                _allFragmentTransmitted = _successfullyTransmittedFragments.CheckAllSet(true);
                                if (_allFragmentTransmitted)
                                {
                                    _currentState = FragmentationMessageState.Final;
                                    messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, Status.Success);

                                }
                                else
                                {
                                    sendData = true;
                                }

                            }
                            else
                            {
                                if (!_allFragmentTransmitted)
                                {
                                    // check if continue sending fragment or wait for ACK.
                                    if (_nbFragmentsSentWithoutAck >= _maxFragmentsBeforeAck)
                                    {
                                        // wait for ack.
                                        _timeLastFragmentSent = DateTime.Now;
                                        _timeoutTicks = _timeLastFragmentSent.Ticks + _timeoutForResending * TimeSpan.TicksPerMillisecond;
                                        _timerId = _timer.RegisterItem(_timeoutTicks, this);
                                        _timerEnabled = true;
                                        _currentState = FragmentationMessageState.WaitingAck;
                                    }
                                    else
                                    {
                                        _timeLastFragmentSent = DateTime.Now;
                                        sendData = true;
                                    }
                                }
                                else
                                {
                                    _currentState = FragmentationMessageState.Final;
                                    messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, Status.Success);
                                }
                            }
                            break;
                        case Status.Timeout:
                        case Status.Busy:
#if DEBUG
                            Trace.Print("stack busy. wait for " + FragmentationMessage.c_timeoutWhenStackBusy + " ms.");
#endif
                            _timeoutTicks = DateTime.Now.Ticks + FragmentationMessage.c_timeoutWhenStackBusy * TimeSpan.TicksPerMillisecond;
                            _timerId = _timer.RegisterItem(_timeoutTicks, this);
                            _timerEnabled = true;
                            _currentState = FragmentationMessageState.WaitingTimeoutBeforeResending;
                            break;
                        case Status.Error:
                        case Status.NoRoute:
                        case Status.NotRunning:
                        case Status.InvalidFrame:
                        default:
                            _currentState = FragmentationMessageState.SendingImpossible;
                            messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, _sendStatus);
                            break;
                    }
                }
            }

            // need to release the lock before calling OnFragmentationMessageFinalState since upper layer handler might be called.
            if (messageTerminatedHandlerArgs != null)
            {
                OnFragmentationMessageTerminated(messageTerminatedHandlerArgs);
            }
            else if (sendData)
            {
                SendNextDataFragment(false);
            }
        }
        override internal void HandleTimeout(Object sender, TimeoutEventArgs args)
        {
            FragmentationMessageTerminatedEventArgs messageTerminatedHandlerArgs = null;
            bool sendData = false;
#if PRINTALL
            Trace.Print("Timeout in outbound message!");
#endif

            lock (_lock)
            {
                if (!_timerEnabled)
                {
#if PRINTALL
                    Trace.Print("timer is not enabled. Do nothing.");
#endif
                    return;
                }

                _timerEnabled = false; // no need to unregister since automatically unregister when timeout is fired.
                if (_currentState == FragmentationMessageState.Disposed)
                {
                    return;
                }

                if (this != args.Message)
                    throw new ArgumentException("timeout delivered with wrong message");
                _nbTimeoutWithoutAck++;
                if (_nbTimeoutWithoutAck >= c_maxNbTimeoutWithoutNewMessage)
                {
                    _sendStatus = Status.Timeout;
                    _currentState = FragmentationMessageState.SendingImpossible;

                    messageTerminatedHandlerArgs = new FragmentationMessageTerminatedEventArgs(_currentState, _sendStatus);
                }
                else
                {
                    _nbFragmentsSentWithoutAck = 0;
                    _lastFragmentSent.SetAll(false);
                    _maxFragmentsBeforeAck /= 2;
                    if (_maxFragmentsBeforeAck == 0)
                    {
                        _maxFragmentsBeforeAck = 1;
                    }

                    _timeoutForResending = (2 * _timeoutForResending);
                    if (_timeoutForResending > c_maxTimeoutForResending)
                    {
                        _timeoutForResending = c_maxTimeoutForResending;
                    }

                    sendData = true;
                }
            }

            if (messageTerminatedHandlerArgs != null)
            {
                OnFragmentationMessageTerminated(messageTerminatedHandlerArgs);
            }
            else if (sendData)
            {
                SendNextDataFragment(true);
            }
        }
        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);
            }
        }
 protected void OnFragmentationMessageTerminated(FragmentationMessageTerminatedEventArgs args)
 {
     FragmentationMessageTerminatedEventHandler handler = FragmentationMessageTerminated;
     if (!_notifcationOfFinalStateTransmitted && (handler != null))
     {
         _notifcationOfFinalStateTransmitted = true;
         handler(this, args);
     }
 }