/// <summary> /// Generate UInt16 corresponding to header. /// </summary> /// <param name="header">header to be encoded</param> /// <returns>UInt16 representation of the header</returns> static public UInt16 Encode(FragmentHeader header) { UInt16 mask; UInt16 value = 0; UInt16 utype = (UInt16)header.Type; mask = 0x0001; // 1 bit for type value |= (UInt16)((utype & mask) << (byte)FragmentHeaderField.Type); value |= (UInt16)(header.MessageSeqNumber << (byte)FragmentHeaderField.MessageNumber); mask = 0x003F; // 6 bits for fragmentSeqNumber value |= (UInt16)((header.FragmentSeqNumber & mask) << (byte)FragmentHeaderField.FragmentSeqNumber); if (header.IsAckRequired) { mask = 0x0001; mask = (UInt16)(mask << (byte)FragmentHeaderField.RequireAck); value |= mask; } return(value); }
/// <summary> /// Create a frame containing a DATA fragment /// </summary> /// <param name="messageSeqNumber">message sequence number</param> /// <param name="fragmentSeqNumber">fragment sequence number</param> /// <param name="isBroadcast">true if fragment is broadcasted</param> /// <param name="requireAck">true if an acknowledgment is required</param> /// <param name="pduSize">max size for the sublayer payload</param> /// <param name="reservedTail">max size for the sublayer tail</param> /// <param name="reservedHead">max size for the sublayer header</param> /// <param name="nbFragments">number of DATA fragments in the message</param> /// <param name="fragmentIndex">index of the DATA fragment</param> /// <param name="payloadData">payload</param> /// <param name="indexPayloadData">start index in the payload </param> /// <param name="nbBytes">number of bytes in the payload</param> /// <returns>the generated frame</returns> public static Frame CreateDataFrame(byte messageSeqNumber, byte fragmentSeqNumber, bool isBroadcast, bool requireAck, int pduSize, int reservedTail, int reservedHead, byte nbFragments, byte fragmentIndex, Frame payloadData, int indexPayloadData, int nbBytes) { if (pduSize < 2 + 2 + nbBytes) { throw new ArgumentException("pdu size is too small", "pduSize"); } FragmentHeader header = new FragmentHeader(FragmentType.DATA, messageSeqNumber, requireAck, fragmentSeqNumber); Frame frame = Frame.GetFrame(reservedHead + reservedTail + 2 + 2 + nbBytes); frame.ReserveHeader(reservedHead); UInt16 serializedHdr = FragmentHeader.Encode(header); frame.AllocBack(4); frame.Write(0, serializedHdr); frame.Write(2, nbFragments); frame.Write(3, fragmentIndex); frame.AppendToBack(payloadData, indexPayloadData, nbBytes); return(frame); }
/// <summary> /// Create a frame containing an ACK fragment /// </summary> /// <param name="messageSeqNumber">message sequence number</param> /// <param name="fragmentSeqNumber">fragment sequence number</param> /// <param name="pduSize">max size for the sublayer payload</param> /// <param name="reservedTail">max size for the sublayer tail</param> /// <param name="reservedHead">max size for the sublayer header</param> /// <param name="lastFragmentSeqNumberReceived">last fragment sequence number received by the receiver</param> /// <param name="fragmentMissingTable">table of missing fragments</param> /// <returns>the generated frame</returns> public static Frame CreateAckFragmentFrame(byte messageSeqNumber, byte fragmentSeqNumber, int pduSize, int reservedTail, int reservedHead, byte lastFragmentSeqNumberReceived, BitArray fragmentMissingTable) { byte[] byteArray = BitArray.ToByteArray(fragmentMissingTable); if (pduSize < 2 /* header */ + 1 /*last frag nb rec. */ + byteArray.Length + 1 /* size bit array */) { throw new ArgumentException("pdu size is too small", "pduSize"); } FragmentHeader header = new FragmentHeader(FragmentType.ACK, messageSeqNumber, false, fragmentSeqNumber); Frame frame = Frame.GetFrame(reservedHead + reservedTail + 2 + 1 + byteArray.Length + 1); frame.ReserveHeader(reservedHead); UInt16 serializedHdr = FragmentHeader.Encode(header); frame.AllocBack(4); frame.Write(0, serializedHdr); frame.Write(2, lastFragmentSeqNumberReceived); frame.Write(3, (byte)fragmentMissingTable.Length); frame.AppendToBack(byteArray, 0, byteArray.Length); return(frame); }
/// <summary> /// Generate UInt16 corresponding to header. /// </summary> /// <param name="header">header to be encoded</param> /// <returns>UInt16 representation of the header</returns> static public UInt16 Encode(FragmentHeader header) { UInt16 mask; UInt16 value = 0; UInt16 utype = (UInt16)header.Type; mask = 0x0001; // 1 bit for type value |= (UInt16)((utype & mask) << (byte)FragmentHeaderField.Type); value |= (UInt16)(header.MessageSeqNumber << (byte)FragmentHeaderField.MessageNumber); mask = 0x003F; // 6 bits for fragmentSeqNumber value |= (UInt16)((header.FragmentSeqNumber & mask) << (byte)FragmentHeaderField.FragmentSeqNumber); if (header.IsAckRequired) { mask = 0x0001; mask = (UInt16)(mask << (byte)FragmentHeaderField.RequireAck); value |= mask; } return value; }
/// <summary> /// Create a frame containing a DATA fragment /// </summary> /// <param name="messageSeqNumber">message sequence number</param> /// <param name="fragmentSeqNumber">fragment sequence number</param> /// <param name="isBroadcast">true if fragment is broadcasted</param> /// <param name="requireAck">true if an acknowledgment is required</param> /// <param name="pduSize">max size for the sublayer payload</param> /// <param name="reservedTail">max size for the sublayer tail</param> /// <param name="reservedHead">max size for the sublayer header</param> /// <param name="nbFragments">number of DATA fragments in the message</param> /// <param name="fragmentIndex">index of the DATA fragment</param> /// <param name="payloadData">payload</param> /// <param name="indexPayloadData">start index in the payload </param> /// <param name="nbBytes">number of bytes in the payload</param> /// <returns>the generated frame</returns> public static Frame CreateDataFrame(byte messageSeqNumber, byte fragmentSeqNumber, bool isBroadcast, bool requireAck, int pduSize, int reservedTail, int reservedHead, byte nbFragments, byte fragmentIndex, Frame payloadData, int indexPayloadData, int nbBytes) { if (pduSize < 2 + 2 + nbBytes) throw new ArgumentException("pdu size is too small", "pduSize"); FragmentHeader header = new FragmentHeader(FragmentType.DATA, messageSeqNumber, requireAck, fragmentSeqNumber); Frame frame = Frame.GetFrame(reservedHead + reservedTail + 2 + 2 + nbBytes); frame.ReserveHeader(reservedHead); UInt16 serializedHdr = FragmentHeader.Encode(header); frame.AllocBack(4); frame.Write(0, serializedHdr); frame.Write(2, nbFragments); frame.Write(3, fragmentIndex); frame.AppendToBack(payloadData, indexPayloadData, nbBytes); return frame; }
/// <summary> /// Create a frame containing an ACK fragment /// </summary> /// <param name="messageSeqNumber">message sequence number</param> /// <param name="fragmentSeqNumber">fragment sequence number</param> /// <param name="pduSize">max size for the sublayer payload</param> /// <param name="reservedTail">max size for the sublayer tail</param> /// <param name="reservedHead">max size for the sublayer header</param> /// <param name="lastFragmentSeqNumberReceived">last fragment sequence number received by the receiver</param> /// <param name="fragmentMissingTable">table of missing fragments</param> /// <returns>the generated frame</returns> public static Frame CreateAckFragmentFrame(byte messageSeqNumber, byte fragmentSeqNumber, int pduSize, int reservedTail, int reservedHead, byte lastFragmentSeqNumberReceived, BitArray fragmentMissingTable) { byte[] byteArray = BitArray.ToByteArray(fragmentMissingTable); if (pduSize < 2 /* header */ + 1 /*last frag nb rec. */ + byteArray.Length + 1 /* size bit array */) throw new ArgumentException("pdu size is too small", "pduSize"); FragmentHeader header = new FragmentHeader(FragmentType.ACK, messageSeqNumber, false, fragmentSeqNumber); Frame frame = Frame.GetFrame(reservedHead + reservedTail + 2 + 1 + byteArray.Length + 1); frame.ReserveHeader(reservedHead); UInt16 serializedHdr = FragmentHeader.Encode(header); frame.AllocBack(4); frame.Write(0, serializedHdr); frame.Write(2, lastFragmentSeqNumberReceived); frame.Write(3, (byte)fragmentMissingTable.Length); frame.AppendToBack(byteArray, 0, byteArray.Length); return frame; }
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); } }
/// <summary> /// Switch to next state after receiving a new segment /// </summary> /// <param name="segment">The segment</param> internal abstract void HandleReceivedFragment(FragmentHeader header, ref Frame payload);
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); } }
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); } }