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