/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

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