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> /// Start sending segments. /// <param name="force">send a fragment in all case if true, do not send if no fragment pending</param> /// </summary> override internal void SendNextDataFragment(bool force) { Frame fragment; ushort target; byte pduHandle; lock (_lock) { if (_timerEnabled) { _timer.UnregisterItem(this); _timerEnabled = false; } if ((_currentState == FragmentationMessageState.Disposed) || (_allFragmentTransmitted)) { return; } // for broadcast message, we send fragment one by one to make sure that they are properly sent. byte indexOfFragmentToSend = 0; bool fragmentFound = false; bool lastFragmentToBeSent = true; for (int i = 0; i < _endingIndices.Length; i++) { if (!_successfullyTransmittedFragments.Get(i) && !_lastFragmentSent.Get(i)) { if (fragmentFound) { lastFragmentToBeSent = false; break; } indexOfFragmentToSend = (byte)i; fragmentFound = true; } } bool alreadySentAll = false; if (!fragmentFound) { if (force) { // no segment to send. Resent last one. alreadySentAll = true; indexOfFragmentToSend = (byte)(_endingIndices.Length - 1); } else { // no fragment to send. Wait for ack. _timeoutTicks = DateTime.Now.Ticks + _timeoutForResending * TimeSpan.TicksPerMillisecond; _timerId = _timer.RegisterItem(_timeoutTicks, this); _timerEnabled = true; _currentState = FragmentationMessageState.WaitingAck; return; } } bool requireAck = false; byte fragmentSeqNumber = ++_lastFragmentSeqNumberSent; if ((!_isBroadcast) && (lastFragmentToBeSent || (_nbFragmentsSentWithoutAck + 1 >= _maxFragmentsBeforeAck) || alreadySentAll)) { requireAck = true; } int startIndexInSdu = (indexOfFragmentToSend == 0) ? 0 : _endingIndices[indexOfFragmentToSend - 1] + 1; int endIndexInSdu = _endingIndices[indexOfFragmentToSend]; fragment = Fragment.CreateDataFrame(_messageSeqNumber, fragmentSeqNumber, _isBroadcast, requireAck, _maxPduSize, _reservedTailSize, _reservedHeaderSize, _nbFragments, indexOfFragmentToSend, _sdu, startIndexInSdu, endIndexInSdu - startIndexInSdu + 1); _nbFragmentsSentWithoutAck++; _nbFragmentsTransmittedLastSendTransition = 0; _lastFragmentSent.Set(indexOfFragmentToSend, true); #if PRINTALL Trace.Print("Sending part " + indexOfFragmentToSend + "/" + _endingIndices.Length.ToString() + " of packet " + _messageSeqNumber); #endif _currentState = FragmentationMessageState.WaitingSentStatus; pduHandle = _pduHandle++; target = _destination; _nbTransmissions++; _nbFragmentsTransmittedLastSendTransition++; // already set time of last fragment sent, but update when receive sent confirmation. // this prevent the situation where the ACK is actually handled before the send confirmation _timeLastFragmentSent = DateTime.Now; } // release lock before calling lower layer handler. _lowerLayerRequestHandler(target, ref fragment, pduHandle, this.HandleSendConfirmation); Frame.Release(ref fragment); return; }