public void SetPrefetchedBytes(byte[] bytes, int offset, int count) { // argument checks if (bytes == null) { throw new ArgumentNullException(nameof(bytes)); } if (offset < 0 || bytes.Length < offset) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (count <= 0 || bytes.Length - offset < count || ComponentFactory.MemoryBlockCache.MemoryBlockSize < count) { // Note that 0-count is not allowed. throw new ArgumentOutOfRangeException(nameof(count)); } // mark the given bytes on the source as prefetched bytes // These bytes are part of the next message. byte[] memoryBlock = ComponentFactory.AllocMemoryBlock(); try { Buffer.BlockCopy(bytes, offset, memoryBlock, 0, count); this.prefetchedBytesLength = count; this.prefetchedBytes = memoryBlock; } catch { ComponentFactory.FreeMemoryBlock(memoryBlock); throw; } return; }
protected override byte[] UpdateMemoryBlock(byte[] currentMemoryBlock) { // calculate the base offset of the next memory block int newBaseOffset = this.currentMemoryBlockBaseOffset; if (currentMemoryBlock == null) { Debug.Assert(newBaseOffset == 0); } else { int increment = currentMemoryBlock.Length; if (int.MaxValue - newBaseOffset < increment) { // header size exceeds 2G throw new Exception("The header size must be smaller than 2G bytes."); } newBaseOffset += currentMemoryBlock.Length; } // allocate a new memory block byte[] newMemoryBlock = this.prefetchedBytes; if (newMemoryBlock != null) { // there is prefetched bytes which were read in the previous message processing this.prefetchedBytes = null; Debug.Assert(0 < this.prefetchedBytesLength); // Do not clear this.prefetchedBytesLength, which is used at the next ReadBytes() call } else { newMemoryBlock = ComponentFactory.AllocMemoryBlock(); } try { this.memoryBlocks.Add(newMemoryBlock); } catch { ComponentFactory.FreeMemoryBlock(newMemoryBlock); throw; } // update its state this.currentMemoryBlockBaseOffset = newBaseOffset; return(newMemoryBlock); }
private static void Forward(ICommunicationOwner owner, CommunicationSubType type) { // argument checks Debug.Assert(owner != null); IMessageIO io; switch (type) { case CommunicationSubType.UpStream: io = owner.RequestIO; break; case CommunicationSubType.DownStream: io = owner.ResponseIO; break; default: throw new ArgumentOutOfRangeException(nameof(type)); } Debug.Assert(io != null); Stream input = io.Input; Debug.Assert(input != null); Stream output = io.Output; Debug.Assert(output != null); // forward bytes from the input to the output try { // notify the owner owner.OnTunnelingStarted(type); // forward bytes byte[] buf = ComponentFactory.AllocMemoryBlock(); try { do { int readCount = input.Read(buf, 0, buf.Length); if (readCount <= 0) { // the end of the stream break; } output.Write(buf, 0, readCount); output.Flush(); } while (true); } catch (EndOfStreamException) { // continue } finally { ComponentFactory.FreeMemoryBlock(buf); } // notify the owner of its normal closing owner.OnTunnelingClosing(type, null); } catch (Exception exception) { // notify the owner of the exception try { owner.OnTunnelingClosing(type, exception); } catch { // continue } // continue } return; }
protected virtual byte[] UpdateMemoryBlock(byte[] currentMemoryBlock) { // by default, reuse one memory block return((currentMemoryBlock != null) ? currentMemoryBlock : ComponentFactory.AllocMemoryBlock()); }