PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Transportation/TcpClientTransport.cs

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