using System; using System.IO; namespace Capnp.Util { internal class DuplexBufferedStream : Stream { // A buffer size of 1024 bytes seems to be a good comprise, giving good performance // in TCP/IP-over-localhost scenarios for small to medium (200kiB) frame sizes. const int DefaultBufferSize = 1024; readonly BufferedStream _readStream; readonly BufferedStream _writeStream; readonly int _bufferSize; readonly object _reentrancyBlocker = new object(); public DuplexBufferedStream(Stream stream, int bufferSize) { _readStream = new BufferedStream(stream, bufferSize); _writeStream = new BufferedStream(stream, bufferSize); _bufferSize = bufferSize; } public DuplexBufferedStream(Stream stream): this(stream, DefaultBufferSize) { } public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => true; public override long Length => 0; public override long Position { get => 0; set => throw new NotSupportedException(); } public override void Flush() { _writeStream.Flush(); } public override int Read(byte[] buffer, int offset, int count) { return _readStream.Read(buffer, offset, count); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { if (buffer.Length > _bufferSize) // avoid moiré-like timing effects _writeStream.Flush(); _writeStream.Write(buffer, offset, count); } protected override void Dispose(bool disposing) { if (disposing) { lock (_reentrancyBlocker) { try { _readStream.Dispose(); } catch { } try { _writeStream.Dispose(); } catch { } } } base.Dispose(disposing); } } }