/// <summary>Implements scan for new packets (invoked internally after reception of new data) and implements stale rx data detection and handling when no new data has been received.</summary> public void Service(bool performFullRescan) { // check for unscanned data if (performFullRescan) lastScannedContentCount = 0; if (BufferDataCount == 0 || BufferDataCount == lastScannedContentCount) return; PacketEndScannerDelegate scannerDelegate = packetEndScannerDelegate ?? defaultPacketEndScannerDelegate ?? (defaultPacketEndScannerDelegate = DefaultPacketEndScannerDelegate); bool foundPacket = false; for (;;) { int bufferDataCount = BufferDataCount; int nextPacketLen = scannerDelegate(buffer, getIdx, bufferDataCount, lastScannedContentCount); if (nextPacketLen == 0) { lastScannedContentCount = bufferDataCount; break; } else { lastScannedContentCount = 0; foundPacket = true; int dataCopyStartIdx = getIdx; bool isFlushedData = (nextPacketLen < 0); nextPacketLen = Math.Abs(nextPacketLen); int dataCopyLen = Math.Min(bufferDataCount, nextPacketLen); bool isWhitespace = false; if (isFlushedData) { // we do not strip whitespace from flushed data. } else if (StripWhitespace) { while (dataCopyLen > 0) { if (!IsWhiteSpace(buffer[dataCopyStartIdx])) break; dataCopyStartIdx++; dataCopyLen--; } while (dataCopyLen > 0) { if (!IsWhiteSpace(buffer[dataCopyStartIdx + dataCopyLen - 1])) break; dataCopyLen--; } isWhitespace = (dataCopyLen == 0); } else { isWhitespace = true; // assume that it is all whitespace for (int scanOffset = 0; scanOffset < dataCopyLen; scanOffset++) { if (!IsWhiteSpace(buffer[getIdx + scanOffset])) isWhitespace = false; } } // extract bytes from buffer and append into new packet if (!isWhitespace || !DiscardWhitespacePackets) { Packet p; if (!isFlushedData) p = new Packet((!isWhitespace ? PacketType.Data : PacketType.WhiteSpace), new byte[dataCopyLen]); else p = new Packet(PacketType.Flushed, new byte[dataCopyLen]); if (dataCopyLen > 0) System.Buffer.BlockCopy(buffer, dataCopyStartIdx, p.Data, 0, dataCopyLen); extractedPacketQueue.Enqueue(p); } UsedNChars(nextPacketLen); } } // drop leading whitespace from buffer immediately (this will prevent them from causing generation of unexpected timeout packets for trailing whitespace that is ignored) if (StripWhitespace && BufferDataCount > 0) { if (IsWhiteSpace(buffer[getIdx])) UsedNChars(1); } // check for timeout: when both the contentPutAge and the contentGetAge are larger than the PacketTimeout and it is not zero. if (!foundPacket && BufferDataCount > 0 && PacketTimeout != TimeSpan.Zero) { QpcTimeStamp now = QpcTimeStamp.Now; TimeSpan contentPutAge = now - ContentPutTime; TimeSpan contentGetAge = now - ContentGetTime; if (contentPutAge > PacketTimeout && contentGetAge > PacketTimeout) { double contentAgeInSec = System.Math.Min(contentPutAge.TotalSeconds, contentGetAge.TotalSeconds); string opStr = ((contentPutAge < contentGetAge) ? "Put" : "Get"); // transfer the current bytes in the sliding buffer into a new packet and reset the sliding buffer Packet p = new Packet(PacketType.Timeout, new byte[BufferDataCount], Utils.Fcns.CheckedFormat("Timeout: {0} stale chars found in buffer {1:f3} seconds after most recent {2}", BufferDataCount, contentAgeInSec, opStr)); System.Buffer.BlockCopy(buffer, getIdx, p.Data, 0, BufferDataCount); extractedPacketQueue.Enqueue(p); UsedNChars(BufferDataCount); } } }
/// <summary>Attempts to extract the next packet from the queue and return it. Returns null if there are currently no packets in the queue.</summary> /// <param name="flushBuffer">When true, if the buffer is not empty, the outstanding bytes will be placed into a flush packet which will be enqueued before attempting to extract and return the next packet from the queue.</param> /// <returns>next Packet from the queue of extracted packets or null if there are none.</returns> public Packet GetNextPacket(bool flushBuffer) { if (flushBuffer) { Service(); int flushCount = BufferDataCount; if (flushCount > 0) { // extract bytes from buffer and append into new packet Packet p = new Packet(PacketType.Flushed, new byte[flushCount]); System.Buffer.BlockCopy(buffer, getIdx, p.Data, 0, flushCount); extractedPacketQueue.Enqueue(p); UsedNChars(flushCount); } } if (extractedPacketQueue.Count != 0) return extractedPacketQueue.Dequeue(); Service(); if (extractedPacketQueue.Count != 0) return extractedPacketQueue.Dequeue(); return null; }