//////////////////////////////////////////////// //// PartnerStream //// //// Version 1.0.0 09.07.04 //// //////////////////////////////////////////////// // P2PLib - Copyright (C) 2004 Daniel Grunwald // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // using System; using System.IO; namespace Grunwald.P2PLib.Server { /// /// This special type of stream only exists in pairs. /// Use the static method Create to create a pair of PartnerStreams. /// Whenever you write something to one stream, it can be read from the other stream. /// /// /// You can use this stream to emulate a socket connection. /// /// void TestPartnerStream() /// { /// PartnerStream s1, s2; /// PartnerStream.Create(out s1, out s2); /// StreamWriter w = new StreamWriter(s1); /// StreamReader r = new StreamReader(s2); /// w.WriteLine("Hello World!"); /// w.Flush(); /// Console.Write(r.ReadLine()); /// } /// /// public class PartnerStream : System.IO.Stream { /// /// Creates a pair of PartnerStreams that are connected with each other. /// public static void Create(out PartnerStream stream1, out PartnerStream stream2) { stream1 = new PartnerStream(); stream2 = new PartnerStream(); stream1.partner = stream2; stream2.partner = stream1; } MemoryStream m = new MemoryStream(); PartnerStream partner; private PartnerStream() { } /// /// Gets a value indicating whether the current stream supports reading. /// The PartnerStream always supports reading as long as it is not closed. /// /// /// Inherited property from base class Stream /// - read only /// public override bool CanRead { get { return partner != null; } } /// /// Gets a value indicating whether the current stream supports seeking. /// The PartnerStream does not support seeking. /// /// /// Inherited property from base class Stream /// - read only /// public override bool CanSeek { get { return false; } } /// /// Gets a value indicating whether the current stream supports writing. /// The PartnerStream always supports writing as long as it is not closed. /// /// /// Inherited property from base class Stream /// - read only /// public override bool CanWrite { get { return partner != null; } } /// /// Gets the length in bytes of the stream. /// The PartnerStream doesn't support this property. /// /// /// Inherited property from base class Stream /// - read only /// public override long Length { get { throw new NotSupportedException(); } } /// /// Gets or sets the position within the current stream. /// This property is not supported by PartnerStream. /// /// /// Inherited property from base class Stream /// - read/write /// public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } MemoryStream writeBuffer = new MemoryStream(); bool autoFlush = false; /// /// Gets or sets a value indicating whether the PartnerStream will flush its /// buffer to the partner after every call to . /// /// /// Turning this property off will call . /// public bool AutoFlush { get { return autoFlush; } set { if (autoFlush && !value) Flush(); autoFlush = value; } } /// /// Writes a sequence of bytes to the partner stream. /// /// /// Inherited method from base class Stream /// /// An array of bytes. This method copies count bytes from buffer to the current stream. /// The zero-based byte offset in buffer at which to begin copying bytes to the current stream. /// The number of bytes to be written to the current stream. public override void Write(byte[] buffer, int offset, int count) { if (partner == null) throw new ObjectDisposedException("PartnerStream"); if (AutoFlush) { MemoryStream m = partner.m; lock(m) { long loc = m.Position; m.Seek(0, SeekOrigin.End); m.Write(buffer, offset, count); m.Position = loc; } } else { lock(writeBuffer) { writeBuffer.Write(buffer, offset, count); } } } /// /// Reads a sequence of bytes from the current stream and advances the /// position within the stream by the number of bytes read. /// /// /// Inherited method from base class Stream /// /// An array of bytes. When this method returns, the buffer /// contains the specified byte array with the values between offset and /// (offset + count- 1) replaced by the bytes read from the current source. /// The zero-based byte offset in buffer at which to /// begin storing the data read from the current stream. /// The maximum number of bytes to be read from the current stream. public override int Read(byte[] buffer, int offset, int count) { if (partner == null) return 0; while(true) { lock(m) { int c = m.Read(buffer, offset, count); if (c == 0) { // Finished reading m.Position = 0; m.SetLength(0); } else { return c; } } System.Threading.Thread.Sleep(50); if (partner == null) return 0; } } /// /// Sets the length of the current stream. /// PartnerStream doesn't support this method. /// /// /// Inherited method from base class Stream /// /// The desired length of the current stream in bytes. public override void SetLength(long value) { throw new NotSupportedException(); } /// /// Sets the position within the current stream. /// PartnerStream doesn't support this method. /// /// /// Inherited method from base class Stream /// /// A byte offset relative to the origin parameter. /// A value of type indicating /// the reference point used to obtain the new position. public override long Seek(long offset, System.IO.SeekOrigin origin) { throw new NotSupportedException(); } /// /// Clears all buffers for this stream and causes any buffered data to be /// written to the underlying device (in this case the partner stream). /// /// /// Inherited method from base class Stream /// public override void Flush() { if (partner == null) return; MemoryStream m = partner.m; lock(writeBuffer) { lock(m) { long loc = m.Position; m.Seek(0, SeekOrigin.End); writeBuffer.WriteTo(m); m.Position = loc; } writeBuffer.Position = 0; writeBuffer.SetLength(0); } } /// /// Closes the current stream and its partner stream. /// /// /// Inherited method from base class Stream /// public override void Close() { if (partner == null) return; base.Close(); PartnerStream p = partner; partner = null; p.Close(); } } }