PageRenderTime 102ms CodeModel.GetById 88ms app.highlight 11ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Manos.IO/Manos.IO.Managed/TcpSocket.cs

http://github.com/jacksonh/manos
C# | 201 lines | 171 code | 30 blank | 0 comment | 20 complexity | e87cb11d7760c50f455658a4fcb0bf9c MD5 | raw file
  1using System;
  2using System.Collections.Generic;
  3using System.Linq;
  4using System.Text;
  5using System.Net.Sockets;
  6using System.Net;
  7using Manos.IO;
  8using System.Threading;
  9
 10namespace Manos.IO.Managed
 11{
 12	class TcpSocket : IPSocket<ByteBuffer, IByteStream>, ITcpSocket, ITcpServerSocket
 13	{
 14		TcpStream stream;
 15		bool wasDisposing;
 16		
 17		class TcpStream : ManagedByteStream, ISendfileCapable
 18		{
 19			TcpSocket parent;
 20			
 21			internal TcpStream (TcpSocket parent)
 22				: base (parent.Context, 4 * 1024)
 23			{
 24				this.parent = parent;
 25			}
 26			
 27			public override long Position {
 28				get { throw new NotSupportedException (); }
 29				set { throw new NotSupportedException (); }
 30			}
 31			
 32			public override bool CanRead {
 33				get { return true; }
 34			}
 35			
 36			public override bool CanWrite {
 37				get { return true; }
 38			}
 39			
 40			protected override void Dispose (bool disposing)
 41			{
 42				if (!parent.disposed) {
 43					parent.socket.BeginDisconnect (false, ar => {
 44						Context.Enqueue (delegate {
 45							try {
 46								((System.Net.Sockets.Socket) ar.AsyncState).EndDisconnect (ar);
 47								((System.Net.Sockets.Socket) ar.AsyncState).Dispose ();
 48							} catch {
 49							}
 50				
 51							RaiseEndOfStream ();
 52							
 53							parent.EndDispose ();
 54				
 55							base.Dispose (disposing);
 56						});
 57					}, parent.socket);
 58				}
 59			}
 60			
 61			protected override void DoRead ()
 62			{
 63				System.Net.Sockets.SocketError se;
 64				parent.socket.BeginReceive (buffer, 0, buffer.Length, SocketFlags.None, out se, ReadCallback, null);
 65			}
 66
 67			void ReadCallback (IAsyncResult ar)
 68			{
 69				Context.Enqueue (delegate {
 70					if (!parent.disposed) {
 71						ResetReadTimeout ();
 72				
 73						System.Net.Sockets.SocketError error;
 74						int len = parent.socket.EndReceive (ar, out error);
 75				
 76						if (error != System.Net.Sockets.SocketError.Success) {
 77							RaiseError (new Manos.IO.SocketException ("Read failure", Errors.ErrorToSocketError (error)));
 78						} else if (len == 0) {
 79							RaiseEndOfStream ();
 80							Close ();
 81						} else {
 82							byte [] newBuffer = new byte [len];
 83							Buffer.BlockCopy (buffer, 0, newBuffer, 0, len);
 84						
 85							RaiseData (new ByteBuffer (newBuffer));
 86							DispatchRead ();
 87						}
 88					}
 89				});
 90			}
 91			
 92			protected override WriteResult WriteSingleFragment (ByteBuffer fragment)
 93			{
 94				parent.socket.BeginSend (fragment.Bytes, fragment.Position, fragment.Length, SocketFlags.None, WriteCallback, null);
 95				return WriteResult.Consume;
 96			}
 97			
 98			void WriteCallback (IAsyncResult ar)
 99			{
100				Context.Enqueue (delegate {
101					if (!parent.disposed) {
102						ResetWriteTimeout ();
103					
104						System.Net.Sockets.SocketError err;
105						parent.socket.EndSend (ar, out err);
106						if (err != System.Net.Sockets.SocketError.Success) {
107							RaiseError (new Manos.IO.SocketException ("Write failure", Errors.ErrorToSocketError (err)));
108						} else {
109							HandleWrite ();
110						}
111					}
112				});
113			}
114			
115			public void SendFile (string file)
116			{
117				parent.socket.BeginSendFile (file, ar => {
118					parent.socket.EndSendFile (ar);
119				}, null);
120			}
121		}
122		
123		public TcpSocket (Context context, AddressFamily addressFamily)
124			: base (context, addressFamily, ProtocolFamily.Tcp)
125		{
126		}
127		
128		TcpSocket (Context context, AddressFamily addressFamily, System.Net.Sockets.Socket socket)
129			: base (context, addressFamily, socket)
130		{
131		}
132		
133		public override void Connect (IPEndPoint endpoint, Action callback, Action<Exception> error)
134		{
135			if (callback == null)
136				throw new ArgumentNullException ("callback");
137			if (error == null)
138				throw new ArgumentNullException ("error");
139			
140			socket.BeginConnect (endpoint.Address.address, endpoint.Port, (ar) => {
141				Context.Enqueue (delegate {
142					if (!disposed) {
143						try {
144							socket.EndConnect (ar);
145							IsConnected = true;
146							callback ();
147						} catch (System.Net.Sockets.SocketException e) {
148							error (new Manos.IO.SocketException ("Connect failure", Errors.ErrorToSocketError (e.SocketErrorCode)));
149						}
150					}
151				});
152			}, null);
153		}
154		
155		protected override void Dispose (bool disposing)
156		{
157			GetSocketStream ().Dispose ();
158			wasDisposing = disposing;
159		}
160		
161		void EndDispose ()
162		{
163			disposed = true;
164			base.Dispose (wasDisposing);
165		}
166		
167		public override IByteStream GetSocketStream ()
168		{
169			CheckDisposed ();
170			
171			if (stream == null) {
172				stream = new TcpStream (this);
173			}
174			return stream;
175		}
176		
177		public void Listen (int backlog, Action<ITcpSocket> callback)
178		{
179			try {
180				socket.Listen (backlog);
181				AcceptOne (callback);
182			} catch (System.Net.Sockets.SocketException e) {
183				throw new Manos.IO.SocketException ("Listen failure", Errors.ErrorToSocketError (e.SocketErrorCode));
184			}
185		}
186		
187		void AcceptOne (Action<ITcpSocket> callback)
188		{
189			socket.BeginAccept (ar => {
190				if (!disposed) {
191					var sock = socket.EndAccept (ar);
192					
193					Context.Enqueue (delegate {
194						callback (new TcpSocket (Context, AddressFamily, sock));
195						AcceptOne (callback);
196					});
197				}
198			}, null);
199		}
200	}
201}