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); } } }
public void HandleLowerLayerDataIndication(object sender, ushort originatorShortAddr, ushort targetShortAddr, Frame sdu) { FragmentationMessage fragMsg = null; FragmentHeader header; lock (_lock) { if ((!_started) || (sdu.LengthDataUsed < 2)) { Frame.Release(ref sdu); return; } // extract fragment header. header = FragmentHeader.Decode(sdu.ReadUInt16(0)); sdu.DeleteFromFront(2); FragmentationMessageAssociationSet associations; switch (header.Type) { case FragmentType.DATA: associations = _inboundAssociations; if (associations == null) { Frame.Release(ref sdu); return; } fragMsg = (InboundFragmentationMessage)associations.GetFragmentationMessage(originatorShortAddr, targetShortAddr); if (fragMsg != null) { // there is already one message with this peer. Check freshness. if (fragMsg.MessageNumber != header.MessageSeqNumber) { int sqnOld = (int)fragMsg.MessageNumber; int sqnNew = (int)header.MessageSeqNumber; int diff = (sqnNew > sqnOld) ? sqnNew - sqnOld : sqnNew - sqnOld + 256; if ((header.MessageSeqNumber == 0) || (diff < 128)) { // data received is most recent. fragMsg.Dispose(); fragMsg = null; } else { // data received is old stuff. Frame.Release(ref sdu); return; } } } if (fragMsg == null) { // new message must be started fragMsg = new InboundFragmentationMessage(originatorShortAddr, targetShortAddr, header.MessageSeqNumber, _lowerLayerDataRequest, _lowerMtu, _lowerHead, _lowerTail, _timer); fragMsg.FragmentationMessageTerminated += this.HandleFragmentationMessageTerminated; associations.SetFragmentationMessage(originatorShortAddr, targetShortAddr, fragMsg); } break; case FragmentType.ACK: associations = _outboundAssociations; if (associations == null) { Frame.Release(ref sdu); return; } fragMsg = (OutboundFragmentationMessage)associations.GetFragmentationMessage(targetShortAddr, originatorShortAddr); if ((fragMsg == null) || (fragMsg.MessageNumber != header.MessageSeqNumber)) { //no one waiting for this segment. Discard. #if DEBUG Trace.Print("No one waiting for this segment. Discard."); #endif Frame.Release(ref sdu); return; } break; default: break; } } // release the lock before calling method in FragmentMessage class if (fragMsg != null) { fragMsg.HandleReceivedFragment(header, ref sdu); } }