////////////////////////////////////////////////
//// 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();
}
}
}