예제 #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="DefaultPipelineProcessor{TPackageInfo}"/> class.
 /// </summary>
 /// <param name="receiveFilter">The initializing receive filter.</param>
 /// <param name="maxPackageLength">The max package size.</param>
 public DefaultPipelineProcessor(IReceiveFilter <TPackageInfo> receiveFilter, int maxPackageLength = 0)
 {
     m_ReceiveFilter    = receiveFilter;
     m_ReceiveCache     = new BufferList();
     m_MaxPackageLength = maxPackageLength;
 }
예제 #2
0
        /// <summary>
        /// Filters the received data.
        /// </summary>
        /// <param name="data">The received data.</param>
        /// <param name="rest">The length of the rest data after filtering.</param>
        /// <returns>the received packageInfo instance</returns>
        public virtual TPackageInfo Filter(BufferList data, out int rest)
        {
            rest = 0;

            int searchEndMarkOffset;
            int searchEndMarkLength;

            var currentSegment = data.Last;
            var readBuffer     = currentSegment.Array;
            var offset         = currentSegment.Offset;
            var length         = currentSegment.Count;

            int totalParsed = 0;

            if (!m_FoundBegin)
            {
                int pos = readBuffer.SearchMark(offset, length, m_BeginSearchState, out totalParsed);

                if (pos < 0)
                {
                    //All received data is part of the begin mark
                    if (m_BeginSearchState.Matched > 0 && data.Total == m_BeginSearchState.Matched)
                    {
                        return(default(TPackageInfo));
                    }

                    //Invalid data, contains invalid data before the regular begin mark
                    State = FilterState.Error;
                    return(default(TPackageInfo));
                }

                //Found the matched begin mark
                if (pos != offset)//But not at the beginning, contains invalid data before the regular begin mark
                {
                    State = FilterState.Error;
                    return(default(TPackageInfo));
                }

                //Found start mark, then search end mark
                m_FoundBegin = true;

                searchEndMarkOffset = offset + totalParsed;

                //Reach end
                if (offset + length <= searchEndMarkOffset)
                {
                    return(default(TPackageInfo));
                }

                searchEndMarkLength = offset + length - searchEndMarkOffset;
            }
            else//Already found begin mark
            {
                searchEndMarkOffset = offset;
                searchEndMarkLength = length;
            }

            while (true)
            {
                int parsedLength;
                var endPos = readBuffer.SearchMark(searchEndMarkOffset, searchEndMarkLength, m_EndSearchState, out parsedLength);

                //Haven't found end mark
                if (endPos < 0)
                {
                    return(default(TPackageInfo));
                }

                totalParsed += parsedLength; //include begin mark if the mark is found in this round receiving
                rest         = length - totalParsed;

                var packageInfo = ResolvePackage(this.GetBufferStream(data));

                if (!ReferenceEquals(packageInfo, default(TPackageInfo)))
                {
                    Reset();
                    return(packageInfo);
                }

                if (rest > 0)
                {
                    searchEndMarkOffset = endPos + m_EndSearchState.Mark.Length;
                    searchEndMarkLength = rest;
                    continue;
                }

                //Not found end mark
                return(default(TPackageInfo));
            }
        }
        /// <summary>
        /// Processes the input segment.
        /// </summary>
        /// <param name="segment">The input segment.</param>
        /// <returns>
        /// the processing result
        /// </returns>
        public virtual ProcessResult Process(ArraySegment <byte> segment)
        {
            var receiveCache = m_ReceiveCache;

            receiveCache.Add(segment);

            var rest = 0;

            var currentReceiveFilter = m_ReceiveFilter;

            SingleItemList <IPackageInfo> singlePackage = null;

            List <IPackageInfo> packageList = null;

            while (true)
            {
                var lastItemLength = receiveCache.Last.Count;
                var packageInfo    = currentReceiveFilter.Filter(receiveCache, out rest);

                if (currentReceiveFilter.State == FilterState.Error)
                {
                    return(ProcessResult.Create(ProcessState.Error));
                }

                if (m_MaxPackageLength > 0)
                {
                    var length = receiveCache.Total;

                    if (length > m_MaxPackageLength)
                    {
                        return(ProcessResult.Create(ProcessState.Error, string.Format("Max package length: {0}, current processed length: {1}", m_MaxPackageLength, length)));
                    }
                }


                var nextReceiveFilter = currentReceiveFilter.NextReceiveFilter;

                // don't reset the filter if no request is resolved
                if (packageInfo != null)
                {
                    currentReceiveFilter.Reset();
                }

                if (nextReceiveFilter != null)
                {
                    currentReceiveFilter = nextReceiveFilter;
                    m_ReceiveFilter      = currentReceiveFilter;
                }

                // continue receive
                if (packageInfo == null)
                {
                    if (rest > 0)
                    {
                        var last = receiveCache.Last;

                        if (rest != lastItemLength)
                        {
                            PushResetData(segment, rest);
                        }

                        continue;
                    }

                    return(ProcessResult.Create(ProcessState.Cached, GetNotNullOne(packageList, singlePackage)));
                }

                if (packageList != null)
                {
                    packageList.Add(packageInfo);
                }
                else if (singlePackage == null)
                {
                    singlePackage = new SingleItemList <IPackageInfo>(packageInfo);
                }
                else
                {
                    if (packageList == null)
                    {
                        packageList = new List <IPackageInfo>();
                    }

                    packageList.Add(singlePackage[0]);
                    packageList.Add(packageInfo);
                    singlePackage = null;
                }

                if (packageInfo is IBufferedPackageInfo && // is a buffered package
                    (packageInfo as IBufferedPackageInfo).Data is BufferList)        // and it uses receive buffer directly
                {
                    // so we need to create a new receive buffer container to use
                    m_ReceiveCache = receiveCache = new BufferList();

                    if (rest <= 0)
                    {
                        return(ProcessResult.Create(ProcessState.Cached, GetNotNullOne(packageList, singlePackage)));
                    }
                }
                else
                {
                    m_ReceiveCache.Clear();

                    if (rest <= 0)
                    {
                        return(ProcessResult.Create(ProcessState.Completed, GetNotNullOne(packageList, singlePackage)));
                    }
                }

                PushResetData(segment, rest);
            }
        }
        /// <summary>
        /// Processes the input segment.
        /// </summary>
        /// <param name="segment">The input segment.</param>
        /// <param name="state">The buffer state.</param>
        /// <returns>
        /// the processing result
        /// </returns>
        public virtual ProcessResult Process(ArraySegment <byte> segment, IBufferState state)
        {
            var receiveCache = m_ReceiveCache;

            receiveCache.Add(segment, state);

            var rest = 0;

            var currentReceiveFilter = m_ReceiveFilter;

            while (true)
            {
                var packageInfo = currentReceiveFilter.Filter(receiveCache, out rest);

                if (currentReceiveFilter.State == FilterState.Error)
                {
                    m_BufferRecycler.Return(receiveCache.GetAllCachedItems(), 0, receiveCache.Count);
                    return(ProcessResult.Create(ProcessState.Error));
                }

                if (m_MaxPackageLength > 0)
                {
                    var length = receiveCache.Total;

                    if (length > m_MaxPackageLength)
                    {
                        m_BufferRecycler.Return(receiveCache.GetAllCachedItems(), 0, receiveCache.Count);
                        return(ProcessResult.Create(ProcessState.Error, string.Format("Max package length: {0}, current processed length: {1}", m_MaxPackageLength, length)));
                    }
                }

                var nextReceiveFilter = currentReceiveFilter.NextReceiveFilter;
                currentReceiveFilter.Reset();

                if (nextReceiveFilter != null)
                {
                    currentReceiveFilter = nextReceiveFilter;
                    m_ReceiveFilter      = currentReceiveFilter;
                }

                //Receive continue
                if (packageInfo == null)
                {
                    if (rest > 0)
                    {
                        if (rest != segment.Count)
                        {
                            ReturnOtherThanLastBuffer();
                            PushResetData(segment, rest, state);
                        }

                        continue;
                    }

                    return(ProcessResult.Create(ProcessState.Cached));
                }

                m_PackageHandler.Handle(packageInfo);

                if (packageInfo is IBufferedPackageInfo && // is a buffered package
                    (packageInfo as IBufferedPackageInfo).Data is BufferList)        // and it uses receive buffer directly
                {
                    // so we need to create a new receive buffer container to use
                    m_ReceiveCache = receiveCache = new BufferList();

                    if (rest <= 0)
                    {
                        return(ProcessResult.Create(ProcessState.Cached));
                    }
                }
                else
                {
                    ReturnOtherThanLastBuffer();

                    if (rest <= 0)
                    {
                        return(ProcessResult.Create(ProcessState.Completed));
                    }
                }

                PushResetData(segment, rest, state);
            }
        }