PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/PRoCon.Core/Remote/Layer/FrostbiteLayerConnection.cs

#
C# | 204 lines | 145 code | 46 blank | 13 comment | 32 complexity | 1e6824397e8ec6af52f1ae34f8435fc9 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0, LGPL-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Net;
  5. using System.Net.Sockets;
  6. namespace PRoCon.Core.Remote.Layer {
  7. using PRoCon.Core.Remote;
  8. public class FrostbiteLayerConnection {
  9. private TcpClient m_tcpConnection;
  10. private NetworkStream m_tcpStream;
  11. private static readonly UInt32 MAX_GARBAGE_BYTES = 4194304;
  12. //private static readonly UInt16 BUFFER_SIZE = 16384;
  13. private byte[] a_receivedBuffer;
  14. private byte[] a_packetStream;
  15. private UInt32 m_ui32SequenceNumber;
  16. public UInt32 AcquireSequenceNumber {
  17. get {
  18. lock (new object()) {
  19. return ++this.m_ui32SequenceNumber;
  20. }
  21. }
  22. }
  23. //private string m_strClientIPPort = String.Empty;
  24. public string IPPort {
  25. get {
  26. string strClientIPPort = String.Empty;
  27. // However if the connection is open just get it straight from the horses mouth.
  28. if (this.m_tcpConnection != null && this.m_tcpConnection.Connected == true) {
  29. strClientIPPort = ((IPEndPoint)this.m_tcpConnection.Client.RemoteEndPoint).Address.ToString() + ":" + ((IPEndPoint)this.m_tcpConnection.Client.RemoteEndPoint).Port.ToString();
  30. }
  31. return strClientIPPort;
  32. }
  33. }
  34. #region Events
  35. public delegate void EmptyParameterHandler(FrostbiteLayerConnection sender);
  36. public event EmptyParameterHandler ConnectionClosed;
  37. public delegate void PacketDispatchHandler(FrostbiteLayerConnection sender, Packet packet);
  38. public event PacketDispatchHandler PacketSent;
  39. public event PacketDispatchHandler PacketReceived;
  40. #endregion
  41. public FrostbiteLayerConnection(TcpClient acceptedConnection) {
  42. this.a_receivedBuffer = new byte[4096];
  43. this.a_packetStream = null;
  44. this.m_tcpConnection = acceptedConnection;
  45. if ((this.m_tcpStream = this.m_tcpConnection.GetStream()) != null) {
  46. this.m_tcpStream.BeginRead(this.a_receivedBuffer, 0, this.a_receivedBuffer.Length, this.ReceiveCallback, this);
  47. }
  48. else {
  49. // Short lived..
  50. this.Shutdown();
  51. }
  52. }
  53. private void SendAsyncCallback(IAsyncResult ar) {
  54. try {
  55. this.m_tcpStream.EndWrite(ar);
  56. if (this.PacketSent != null) {
  57. FrostbiteConnection.RaiseEvent(this.PacketSent.GetInvocationList(), this, (Packet)ar.AsyncState);
  58. }
  59. }
  60. catch (SocketException) {
  61. this.Shutdown();
  62. }
  63. catch (Exception) {
  64. this.Shutdown();
  65. }
  66. }
  67. public void SendAsync(Packet cpPacket) {
  68. try {
  69. byte[] a_bBytePacket = cpPacket.EncodePacket();
  70. this.m_tcpStream.BeginWrite(a_bBytePacket, 0, a_bBytePacket.Length, this.SendAsyncCallback, cpPacket);
  71. }
  72. catch (SocketException) {
  73. // TO DO: Error reporting, possibly in a log file.
  74. this.Shutdown();
  75. }
  76. catch (Exception) {
  77. this.Shutdown();
  78. }
  79. }
  80. private void ReceiveCallback(IAsyncResult ar) {
  81. if (this.m_tcpStream != null) {
  82. try {
  83. int iBytesRead = this.m_tcpStream.EndRead(ar);
  84. if (iBytesRead > 0) {
  85. // Create or resize our packet stream to hold the new data.
  86. if (this.a_packetStream == null) {
  87. this.a_packetStream = new byte[iBytesRead];
  88. }
  89. else {
  90. Array.Resize(ref this.a_packetStream, this.a_packetStream.Length + iBytesRead);
  91. }
  92. Array.Copy(this.a_receivedBuffer, 0, this.a_packetStream, this.a_packetStream.Length - iBytesRead, iBytesRead);
  93. UInt32 ui32PacketSize = Packet.DecodePacketSize(this.a_packetStream);
  94. while (this.a_packetStream.Length >= ui32PacketSize && this.a_packetStream.Length > Packet.INT_PACKET_HEADER_SIZE) {
  95. // Copy the complete packet from the beginning of the stream.
  96. byte[] a_bCompletePacket = new byte[ui32PacketSize];
  97. Array.Copy(this.a_packetStream, a_bCompletePacket, ui32PacketSize);
  98. Packet cpCompletePacket = new Packet(a_bCompletePacket);
  99. this.m_ui32SequenceNumber = Math.Max(this.m_ui32SequenceNumber, cpCompletePacket.SequenceNumber);
  100. // Dispatch the completed packet.
  101. if (this.PacketReceived != null) {
  102. FrostbiteConnection.RaiseEvent(this.PacketReceived.GetInvocationList(), this, cpCompletePacket);
  103. }
  104. //this.DispatchPacket(cpCompletePacket);
  105. // Now remove the completed packet from the beginning of the stream
  106. byte[] a_bUpdatedSteam = new byte[this.a_packetStream.Length - ui32PacketSize];
  107. Array.Copy(this.a_packetStream, ui32PacketSize, a_bUpdatedSteam, 0, this.a_packetStream.Length - ui32PacketSize);
  108. this.a_packetStream = a_bUpdatedSteam;
  109. ui32PacketSize = Packet.DecodePacketSize(this.a_packetStream);
  110. }
  111. // If we've recieved 16 kb's and still don't have a full command then shutdown the connection.
  112. if (this.a_receivedBuffer.Length >= FrostbiteLayerConnection.MAX_GARBAGE_BYTES) {
  113. this.a_receivedBuffer = null;
  114. this.Shutdown();
  115. }
  116. }
  117. if (iBytesRead == 0) {
  118. this.Shutdown();
  119. return;
  120. }
  121. IAsyncResult result = this.m_tcpStream.BeginRead(this.a_receivedBuffer, 0, this.a_receivedBuffer.Length, this.ReceiveCallback, null);
  122. if (result.AsyncWaitHandle.WaitOne(180000, false) == false) {
  123. this.Shutdown();
  124. }
  125. }
  126. catch (Exception) {
  127. this.Shutdown();
  128. }
  129. }
  130. }
  131. // TO DO: Better error reporting on this method.
  132. public void Shutdown() {
  133. try {
  134. if (this.ConnectionClosed != null) {
  135. FrostbiteConnection.RaiseEvent(this.ConnectionClosed.GetInvocationList(), this);
  136. }
  137. if (this.m_tcpConnection != null) {
  138. lock (new object()) {
  139. if (this.m_tcpStream != null) {
  140. this.m_tcpStream.Close();
  141. this.m_tcpStream.Dispose();
  142. this.m_tcpStream = null;
  143. }
  144. if (this.m_tcpConnection != null) {
  145. this.m_tcpConnection.Close();
  146. this.m_tcpConnection = null;
  147. }
  148. }
  149. }
  150. }
  151. catch (SocketException) {
  152. // TO DO: Error reporting, possibly in a log file.
  153. }
  154. catch (Exception) {
  155. }
  156. }
  157. }
  158. }