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