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

/Transportation/TcpServerTransport.cs

https://gitlab.com/frank-pti/datacollector
C# | 195 lines | 141 code | 17 blank | 37 comment | 17 complexity | 108753ced4f619b3402e35dcd756687c MD5 | raw file
Possible License(s): AGPL-3.0
  1. using Datacollector.Configuration;
  2. using Datacollector.Transportation.AsyncStates;
  3. using Internationalization;
  4. using Logging;
  5. using ProbeNet.Backend;
  6. /*
  7. * The base library for collecting data from measurement devices
  8. * Copyright (C) Wolfgang Silbermayr
  9. * Copyright (C) Florian Marchl
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Affero General Public License as
  13. * published by the Free Software Foundation, either version 3 of the
  14. * License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU Affero General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. */
  24. using System;
  25. using System.Net;
  26. using System.Net.Sockets;
  27. namespace Datacollector.Transportation
  28. {
  29. /// <summary>
  30. /// Transport for using TCP server connection.
  31. /// </summary>
  32. [TranslatableCaption(Constants.DataCollectorDomain, "TCP connection, server on this computer")]
  33. [TransportTypeIdentifier("TcpServerTransport")]
  34. public class TcpServerTransport : Transport
  35. {
  36. private Socket listenSocket;
  37. private Socket dataSocket;
  38. /// <summary>
  39. /// Initializes a new instance of the <see cref="Datacollector.Transportation.TcpServerTransport"/> class.
  40. /// </summary>
  41. /// <param name="handle">Handle.</param>
  42. public TcpServerTransport(Handle handle)
  43. {
  44. Port = 8080;
  45. }
  46. /// <summary>
  47. /// Gets or sets the TCP port.
  48. /// </summary>
  49. /// <value>The port.</value>
  50. public int Port
  51. {
  52. get;
  53. set;
  54. }
  55. /// <inheritdoc/>
  56. protected override void Connect()
  57. {
  58. State = ConnectionState.Connecting;
  59. listenSocket = new Socket(AddressFamily.InterNetwork,
  60. SocketType.Stream,
  61. ProtocolType.Tcp);
  62. IPAddress hostIp = IPAddress.Any;
  63. IPEndPoint endPoint = new IPEndPoint(hostIp, Port);
  64. listenSocket.Bind(endPoint);
  65. listenSocket.Listen(1);
  66. BeginAccept();
  67. }
  68. private void BeginAccept()
  69. {
  70. State = ConnectionState.Connected;
  71. try {
  72. listenSocket.BeginAccept(OnSocketAccept, null);
  73. } catch (ObjectDisposedException) {
  74. // silently ignore, this happens when shutting down the interface
  75. State = ConnectionState.Disconnected;
  76. }
  77. }
  78. private void OnSocketAccept(IAsyncResult result)
  79. {
  80. try {
  81. dataSocket = listenSocket.EndAccept(result);
  82. SocketReceiveState receiveState = new SocketReceiveState(dataSocket, 1024);
  83. BeginReceive(receiveState);
  84. State = ConnectionState.Connected;
  85. } catch (ObjectDisposedException) {
  86. // silently ignore, this happens when shutting down the interface
  87. State = ConnectionState.Disconnected;
  88. } catch (Exception e) {
  89. NotifyExceptionCaught(e);
  90. }
  91. }
  92. private void BeginReceive(SocketReceiveState receiveState)
  93. {
  94. receiveState.Socket.BeginReceive(receiveState.Buffer, 0, receiveState.Buffer.Length, SocketFlags.None, OnDataReceived, receiveState);
  95. }
  96. private void OnDataReceived(IAsyncResult result)
  97. {
  98. SocketReceiveState receiveState = result.AsyncState as SocketReceiveState;
  99. int count = 0;
  100. try {
  101. count = receiveState.Socket.EndReceive(result);
  102. if (count != 0) {
  103. byte[] buffer = new byte[count];
  104. Array.Copy(receiveState.Buffer, buffer, count);
  105. NotifyDataReceived(buffer);
  106. }
  107. } catch (SocketException e) {
  108. if (e.SocketErrorCode == SocketError.ConnectionReset) {
  109. Logger.Error("TCP Server: remote end disconnected, waiting for incoming connection");
  110. }
  111. } catch (Exception e) {
  112. NotifyExceptionCaught(e);
  113. } finally {
  114. if (count == 0) {
  115. BeginAccept();
  116. } else {
  117. BeginReceive(receiveState);
  118. }
  119. }
  120. }
  121. /// <inheritdoc/>
  122. protected override void Disconnect()
  123. {
  124. State = ConnectionState.Disconnecting;
  125. if (dataSocket != null && dataSocket.Connected) {
  126. dataSocket.Shutdown(SocketShutdown.Both);
  127. dataSocket.Close();
  128. }
  129. listenSocket.Close();
  130. State = ConnectionState.Disconnected;
  131. }
  132. /// <inheritdoc/>
  133. public override void SendData(byte[] data, int offset, int count)
  134. {
  135. if (dataSocket == null || !dataSocket.Connected) {
  136. throw new InvalidOperationException("The socket you want to send data on is not connected");
  137. }
  138. Logger.Log("sending: {0}", System.Text.Encoding.ASCII.GetString(data, offset, count));
  139. dataSocket.BeginSend(data, offset, count, SocketFlags.None, OnDataSent, null);
  140. }
  141. private void OnDataSent(IAsyncResult result)
  142. {
  143. if (dataSocket.Connected) {
  144. try {
  145. dataSocket.EndSend(result);
  146. } catch (SocketException e) {
  147. if (e.SocketErrorCode == SocketError.Shutdown) {
  148. // silently ignore, this happens when the other end disconnects
  149. State = ConnectionState.Connecting;
  150. } else {
  151. NotifyExceptionCaught(e);
  152. }
  153. } catch (Exception e) {
  154. NotifyExceptionCaught(e);
  155. }
  156. }
  157. }
  158. /// <inheritdoc/>
  159. public override DataSourceConfiguration<D> BuildDatasourceConfiguration<D>(D settings)
  160. {
  161. GenericDataSourceConfiguration<TcpServerTransportSettings, D> configuration =
  162. new GenericDataSourceConfiguration<TcpServerTransportSettings, D>(
  163. settings,
  164. new TcpServerTransportSettings() {
  165. Port = Port
  166. });
  167. return configuration as DataSourceConfiguration<D>;
  168. }
  169. /// <inheritdoc/>
  170. public override bool MustDeleteDataBeforeUse
  171. {
  172. get
  173. {
  174. return false;
  175. }
  176. }
  177. }
  178. }