Esempio n. 1
0
        /// <summary>
        /// Check whether exactly the same bits are set into both bit arrays.
        /// </summary>
        /// <param name="other"></param>
        /// <returns>true if all bit values match, false otherwise.</returns>
        public bool HasSameContent(BitArray other)
        {
            if (_size != other._size) { return false; }

            for (int i = 0; i < _array.Length - 1; i++)
            {
                if (_array[i] != other._array[i])
                    return false;
            }

            // last uint32 might not be completed.
            int nbElts = _size % 32;
            UInt32 mask = 0xFFFFFFFF >> (32 - nbElts);
            // set to 0 all the bits which do not correspond to elements
            UInt32 last = mask & _array[_array.Length - 1];
            UInt32 lastOther = mask & other._array[_array.Length - 1];
            return (last == lastOther);
        }
Esempio n. 2
0
 /// <summary>
 /// Decode an ACK fragment payload
 /// </summary>
 /// <param name="payload">payload</param>
 /// <param name="lastFragmentSeqNumberReceived">last fragment sequence number received</param>
 /// <param name="fragmentMissingTable">table of indices of the missing fragments</param>
 public static void DecodeAckPayload(ref Frame payload, out byte lastFragmentSeqNumberReceived, out BitArray fragmentMissingTable)
 {
     if (payload.LengthDataUsed < 2)
         throw new ArgumentException("payload content too small", "payload");
     lastFragmentSeqNumberReceived = payload.ReadByte(0);
     int nbFragments = (int)payload.ReadByte(1);
     byte[] byteArray = new byte[payload.LengthDataUsed - 2];
     payload.ReadBytes(byteArray, 0, 2, payload.LengthDataUsed - 2);
     fragmentMissingTable = BitArray.FromByteArray(nbFragments, byteArray);
     Frame.Release(ref payload);
 }
Esempio n. 3
0
        /// <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 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 OutboundFragmentationMessage(
            UInt16 source,
            UInt16 destination,
            byte messageSeqNumber,
            DataRequestHandler lowerLayerRequestHandler,
            ref Frame sdu,
            Byte sduHandle,
            DataConfirmHandler handler,
            int maxPduSize,
            int reservedHeaderSize,
            int reservedTailSize,
            FragmentationMessageTimer timer
            )
            : base(source, destination, messageSeqNumber, lowerLayerRequestHandler, maxPduSize, reservedHeaderSize, reservedTailSize, timer)
        {
            if (sdu.LengthDataUsed == 0)
            {
                Frame.Release(ref sdu);
                throw new ArgumentException("sdu is empty", "sdu");
            }

            int payloadSize = maxPduSize - 2 - 2; // 2 for our own header, 1 for nb fragment, 1 for fragment id
            if (payloadSize == 0)
            {
                Frame.Release(ref sdu);
                throw new ArgumentException("PDU is too small", "maxPduSize");
            }

            ushort flag = (ushort)(1 << 15);
            _isBroadcast = (destination & flag) > 0 ? true : false;

            _sdu = sdu;
            sdu = null;
            _sduHandle = sduHandle;
            _dataConfirmHandler = handler;
            _messageSeqNumber = messageSeqNumber;
            _timeoutForResending = c_defaultTimeoutForResending;
            _maxFragmentsBeforeAck = c_defaultMaxFragmentsBeforeAck;
            // compute required nb fragments and respective indices.

            int nbFragments = ((_sdu.LengthDataUsed % payloadSize) == 0) ? _sdu.LengthDataUsed / payloadSize : 1 + _sdu.LengthDataUsed / payloadSize;
            if (nbFragments > byte.MaxValue)
                throw new ArgumentException("sdu is too large.");
            _nbFragments = (byte)nbFragments;
            _endingIndices = new int[_nbFragments];
            int lastIndex = -1;
            for (int i = 0; i + 1 < _nbFragments; i++)
            {
                lastIndex += payloadSize;
                _endingIndices[i] = lastIndex;
            }

            lastIndex += ((_sdu.LengthDataUsed % payloadSize) == 0) ? payloadSize : _sdu.LengthDataUsed % payloadSize;
            _endingIndices[_nbFragments - 1] = lastIndex;
            _successfullyTransmittedFragments = new BitArray(_nbFragments, false);
            _lastFragmentSent = new BitArray(_nbFragments, false);
        }
Esempio n. 6
0
 /// <summary>
 /// Clone the BitArray
 /// </summary>
 /// <returns>the clone BitArray</returns>
 public BitArray Clone()
 {
     BitArray clone = new BitArray(_size, false);
     Array.Copy(_array, clone._array, _array.Length);
     return clone;
 }
Esempio n. 7
0
        /// <summary>
        /// Converts a byte array (small indian: first byte includes first elements) into a BitArray
        /// </summary>
        /// <param name="nbElements">number of elements</param>
        /// <param name="array">encoding of the BitArray</param>
        /// <returns>decoded bitarray</returns>
        static public BitArray FromByteArray(int nbElements, byte[] array)
        {
            if (nbElements > array.Length * 8)
                throw new ArgumentException("nbElements");
            BitArray bitArray = new BitArray(nbElements, false);
            int index = 0;
            int arrayLength = array.Length;
            for (int i = 0; index < arrayLength; i++)
            {
                for (int j = 0; j < 4 && index < array.Length; j++, index++)
                {
                    bitArray._array[i] |= ((UInt32)array[index]) << (j * 8);
                }
            }

            return bitArray;
        }
Esempio n. 8
0
        /// <summary>
        /// Converts a BitArray into an array of bytes (small endian: first byte includes first elements)
        /// </summary>
        /// <param name="bitArray">the BitArray to be converted</param>
        /// <returns>the arry of bytes encoding the BitArray</returns>
        static public byte[] ToByteArray(BitArray bitArray)
        {
            int byteArrayLength = ((bitArray._size % 8) == 0) ? (bitArray._size / 8) : 1 + (bitArray._size / 8);
            byte[] byteArray = new byte[byteArrayLength];
            int index = 0;
            for (int i = 0; index < byteArrayLength; i++)
            {
                UInt32 val = bitArray._array[i];
                for (int j = 0; j < 4 && index < byteArrayLength; j++, index++)
                {
                    byteArray[index] = (byte)(val & 0x000000FF);
                    val = val >> 8;
                }
            }

            return byteArray;
        }
Esempio n. 9
0
        /// <summary>
        /// Performs the bitwise OR operation on the elements in the current BitArray against
        /// the corresponding elements in the specified BitArray
        /// </summary>
        /// <param name="value">The BitArray with which to perform the bitwise OR operation. </param>
        public void Or(BitArray value)
        {
            if (value.Length != this.Length)
                throw new ArgumentException("lenght mismatch.", "value");

            for (int i = 0; i < _array.Length; i++)
            {
                this._array[i] = this._array[i] | value._array[i];
            }
        }