// // System.Net.Sockets.NetworkStream.cs // // Author: // Miguel de Icaza (miguel@ximian.com) // // (C) 2002 Ximian, Inc. http://www.ximian.com // using System.IO; using System.Runtime.InteropServices; namespace System.Net.Sockets { public class NetworkStream : Stream, IDisposable { FileAccess access; Socket socket; bool owns_socket; bool readable, writeable; bool disposed = false; public NetworkStream (Socket socket) : this (socket, FileAccess.ReadWrite, false) { } public NetworkStream (Socket socket, bool owns_socket) : this (socket, FileAccess.ReadWrite, owns_socket) { } public NetworkStream (Socket socket, FileAccess access) : this (socket, access, false) { } public NetworkStream (Socket socket, FileAccess access, bool owns_socket) { if (socket == null) throw new ArgumentNullException ("socket is null"); if (!socket.Connected) throw new ArgumentException ("Not connected", "socket"); if (socket.SocketType != SocketType.Stream) throw new ArgumentException ("Socket is not of type Stream", "socket"); if (!socket.Blocking) throw new IOException (); this.socket = socket; this.owns_socket = owns_socket; this.access = access; readable = CanRead; writeable = CanWrite; } public override bool CanRead { get { return access == FileAccess.ReadWrite || access == FileAccess.Read; } } public override bool CanSeek { get { // network sockets cant seek. return false; } } public override bool CanWrite { get { return access == FileAccess.ReadWrite || access == FileAccess.Write; } } public virtual bool DataAvailable { get { CheckDisposed (); return socket.Available > 0; } } public override long Length { get { // Network sockets always throw an exception throw new NotSupportedException (); } } public override long Position { get { // Network sockets always throw an exception throw new NotSupportedException (); } set { // Network sockets always throw an exception throw new NotSupportedException (); } } protected bool Readable { get { return readable; } set { readable = value; } } protected Socket Socket { get { return socket; } } protected bool Writeable { get { return writeable; } set { writeable = value; } } public override IAsyncResult BeginRead (byte [] buffer, int offset, int size, AsyncCallback callback, object state) { CheckDisposed (); IAsyncResult retval; if (buffer == null) throw new ArgumentNullException ("buffer is null"); int len = buffer.Length; if(offset<0 || offset>len) { throw new ArgumentOutOfRangeException("offset exceeds the size of buffer"); } if(size<0 || offset+size>len) { throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer"); } try { retval = socket.BeginReceive (buffer, offset, size, 0, callback, state); } catch { throw new IOException ("BeginReceive failure"); } return retval; } public override IAsyncResult BeginWrite (byte [] buffer, int offset, int size, AsyncCallback callback, object state) { CheckDisposed (); IAsyncResult retval; if (buffer == null) throw new ArgumentNullException ("buffer is null"); int len = buffer.Length; if(offset<0 || offset>len) { throw new ArgumentOutOfRangeException("offset exceeds the size of buffer"); } if(size<0 || offset+size>len) { throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer"); } try { retval = socket.BeginSend (buffer, offset, size, 0, callback, state); } catch { throw new IOException ("BeginWrite failure"); } return retval; } ~NetworkStream () { Dispose (false); } public override void Close () { ((IDisposable) this).Dispose (); } protected virtual void Dispose (bool disposing) { if (disposed) return; disposed = true; if (owns_socket) { Socket s = socket; if (s != null) s.Close (); } socket = null; } public override int EndRead (IAsyncResult ar) { CheckDisposed (); int res; if (ar == null) throw new ArgumentNullException ("async result is null"); try { res = socket.EndReceive (ar); } catch (Exception e) { throw new IOException ("EndRead failure", e); } return res; } public override void EndWrite (IAsyncResult ar) { CheckDisposed (); if (ar == null) throw new ArgumentNullException ("async result is null"); try { socket.EndSend (ar); } catch (Exception e) { throw new IOException ("EndWrite failure", e); } } public override void Flush () { // network streams are non-buffered, this is a no-op } void IDisposable.Dispose () { Dispose (true); GC.SuppressFinalize (this); } public override int Read ([In,Out] byte [] buffer, int offset, int size) { CheckDisposed (); int res; if (buffer == null) throw new ArgumentNullException ("buffer is null"); if(offset<0 || offset>buffer.Length) { throw new ArgumentOutOfRangeException("offset exceeds the size of buffer"); } if(size < 0 || offset+size>buffer.Length) { throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer"); } try { res = socket.Receive (buffer, offset, size, 0); } catch (Exception e) { throw new IOException ("Read failure", e); } return res; } public override long Seek (long offset, SeekOrigin origin) { // NetworkStream objects do not support seeking. throw new NotSupportedException (); } public override void SetLength (long value) { // NetworkStream objects do not support SetLength throw new NotSupportedException (); } public override void Write (byte [] buffer, int offset, int size) { CheckDisposed (); if (buffer == null) throw new ArgumentNullException ("buffer"); if (offset < 0 || offset > buffer.Length) throw new ArgumentOutOfRangeException("offset exceeds the size of buffer"); if (size < 0 || size > buffer.Length - offset) throw new ArgumentOutOfRangeException("offset+size exceeds the size of buffer"); try { socket.Send (buffer, offset, size, 0); } catch (Exception e) { throw new IOException ("Write failure", e); } } private void CheckDisposed () { if (disposed) throw new ObjectDisposedException (GetType().FullName); } } }