/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
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Net.Sockets;
- using System.Net;
- using Manos.IO;
- using System.Threading;
- namespace Manos.IO.Managed
- {
- class TcpSocket : IPSocket<ByteBuffer, IByteStream>, ITcpSocket, ITcpServerSocket
- {
- TcpStream stream;
- bool wasDisposing;
-
- class TcpStream : ManagedByteStream, ISendfileCapable
- {
- TcpSocket parent;
-
- internal TcpStream (TcpSocket parent)
- : base (parent.Context, 4 * 1024)
- {
- this.parent = parent;
- }
-
- public override long Position {
- get { throw new NotSupportedException (); }
- set { throw new NotSupportedException (); }
- }
-
- public override bool CanRead {
- get { return true; }
- }
-
- public override bool CanWrite {
- get { return true; }
- }
-
- protected override void Dispose (bool disposing)
- {
- if (!parent.disposed) {
- parent.socket.BeginDisconnect (false, ar => {
- Context.Enqueue (delegate {
- try {
- ((System.Net.Sockets.Socket) ar.AsyncState).EndDisconnect (ar);
- ((System.Net.Sockets.Socket) ar.AsyncState).Dispose ();
- } catch {
- }
-
- RaiseEndOfStream ();
-
- parent.EndDispose ();
-
- base.Dispose (disposing);
- });
- }, parent.socket);
- }
- }
-
- protected override void DoRead ()
- {
- System.Net.Sockets.SocketError se;
- parent.socket.BeginReceive (buffer, 0, buffer.Length, SocketFlags.None, out se, ReadCallback, null);
- }
- void ReadCallback (IAsyncResult ar)
- {
- Context.Enqueue (delegate {
- if (!parent.disposed) {
- ResetReadTimeout ();
-
- System.Net.Sockets.SocketError error;
- int len = parent.socket.EndReceive (ar, out error);
-
- if (error != System.Net.Sockets.SocketError.Success) {
- RaiseError (new Manos.IO.SocketException ("Read failure", Errors.ErrorToSocketError (error)));
- } else if (len == 0) {
- RaiseEndOfStream ();
- Close ();
- } else {
- byte [] newBuffer = new byte [len];
- Buffer.BlockCopy (buffer, 0, newBuffer, 0, len);
-
- RaiseData (new ByteBuffer (newBuffer));
- DispatchRead ();
- }
- }
- });
- }
-
- protected override WriteResult WriteSingleFragment (ByteBuffer fragment)
- {
- parent.socket.BeginSend (fragment.Bytes, fragment.Position, fragment.Length, SocketFlags.None, WriteCallback, null);
- return WriteResult.Consume;
- }
-
- void WriteCallback (IAsyncResult ar)
- {
- Context.Enqueue (delegate {
- if (!parent.disposed) {
- ResetWriteTimeout ();
-
- System.Net.Sockets.SocketError err;
- parent.socket.EndSend (ar, out err);
- if (err != System.Net.Sockets.SocketError.Success) {
- RaiseError (new Manos.IO.SocketException ("Write failure", Errors.ErrorToSocketError (err)));
- } else {
- HandleWrite ();
- }
- }
- });
- }
-
- public void SendFile (string file)
- {
- parent.socket.BeginSendFile (file, ar => {
- parent.socket.EndSendFile (ar);
- }, null);
- }
- }
-
- public TcpSocket (Context context, AddressFamily addressFamily)
- : base (context, addressFamily, ProtocolFamily.Tcp)
- {
- }
-
- TcpSocket (Context context, AddressFamily addressFamily, System.Net.Sockets.Socket socket)
- : base (context, addressFamily, socket)
- {
- }
-
- public override void Connect (IPEndPoint endpoint, Action callback, Action<Exception> error)
- {
- if (callback == null)
- throw new ArgumentNullException ("callback");
- if (error == null)
- throw new ArgumentNullException ("error");
-
- socket.BeginConnect (endpoint.Address.address, endpoint.Port, (ar) => {
- Context.Enqueue (delegate {
- if (!disposed) {
- try {
- socket.EndConnect (ar);
- IsConnected = true;
- callback ();
- } catch (System.Net.Sockets.SocketException e) {
- error (new Manos.IO.SocketException ("Connect failure", Errors.ErrorToSocketError (e.SocketErrorCode)));
- }
- }
- });
- }, null);
- }
-
- protected override void Dispose (bool disposing)
- {
- GetSocketStream ().Dispose ();
- wasDisposing = disposing;
- }
-
- void EndDispose ()
- {
- disposed = true;
- base.Dispose (wasDisposing);
- }
-
- public override IByteStream GetSocketStream ()
- {
- CheckDisposed ();
-
- if (stream == null) {
- stream = new TcpStream (this);
- }
- return stream;
- }
-
- public void Listen (int backlog, Action<ITcpSocket> callback)
- {
- try {
- socket.Listen (backlog);
- AcceptOne (callback);
- } catch (System.Net.Sockets.SocketException e) {
- throw new Manos.IO.SocketException ("Listen failure", Errors.ErrorToSocketError (e.SocketErrorCode));
- }
- }
-
- void AcceptOne (Action<ITcpSocket> callback)
- {
- socket.BeginAccept (ar => {
- if (!disposed) {
- var sock = socket.EndAccept (ar);
-
- Context.Enqueue (delegate {
- callback (new TcpSocket (Context, AddressFamily, sock));
- AcceptOne (callback);
- });
- }
- }, null);
- }
- }
- }