No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

224 líneas
6.5 KiB

  1. #if NET452 || NET461 || NETSTANDARD1_3 || NETSTANDARD2_0
  2. using System;
  3. using System.Net.Security;
  4. using System.Net.Sockets;
  5. using System.Security.Authentication;
  6. using System.Security.Cryptography.X509Certificates;
  7. using System.Threading.Tasks;
  8. using System.IO;
  9. using System.Linq;
  10. using MQTTnet.Channel;
  11. using MQTTnet.Client;
  12. namespace MQTTnet.Implementations
  13. {
  14. public sealed class MqttTcpChannel : IMqttChannel
  15. {
  16. #if NET452 || NET461
  17. // ReSharper disable once MemberCanBePrivate.Global
  18. // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global
  19. public static int BufferSize { get; set; } = 4096 * 20; // Can be changed for fine tuning by library user.
  20. private readonly int _bufferSize = BufferSize;
  21. #else
  22. private readonly int _bufferSize = 0;
  23. #endif
  24. private readonly MqttClientTcpOptions _options;
  25. private Socket _socket;
  26. private SslStream _sslStream;
  27. /// <summary>
  28. /// called on client sockets are created in connect
  29. /// </summary>
  30. public MqttTcpChannel(MqttClientTcpOptions options)
  31. {
  32. _options = options ?? throw new ArgumentNullException(nameof(options));
  33. _bufferSize = options.BufferSize;
  34. }
  35. /// <summary>
  36. /// called on server, sockets are passed in
  37. /// connect will not be called
  38. /// </summary>
  39. public MqttTcpChannel(Socket socket, SslStream sslStream)
  40. {
  41. _socket = socket ?? throw new ArgumentNullException(nameof(socket));
  42. _sslStream = sslStream;
  43. CreateStreams();
  44. }
  45. public Stream SendStream { get; private set; }
  46. public Stream ReceiveStream { get; private set; }
  47. public static Func<X509Certificate, X509Chain, SslPolicyErrors, MqttClientTcpOptions, bool> CustomCertificateValidationCallback { get; set; }
  48. public async Task ConnectAsync()
  49. {
  50. if (_socket == null)
  51. {
  52. _socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
  53. }
  54. #if NET452 || NET461
  55. await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false);
  56. #else
  57. await _socket.ConnectAsync(_options.Server, _options.GetPort()).ConfigureAwait(false);
  58. #endif
  59. if (_options.TlsOptions.UseTls)
  60. {
  61. _sslStream = new SslStream(new NetworkStream(_socket, true), false, InternalUserCertificateValidationCallback);
  62. await _sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), SslProtocols.Tls12, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false);
  63. }
  64. CreateStreams();
  65. }
  66. public Task DisconnectAsync()
  67. {
  68. Dispose();
  69. return Task.FromResult(0);
  70. }
  71. public void Dispose()
  72. {
  73. var oneStreamIsUsed = SendStream != null && ReceiveStream != null && ReferenceEquals(SendStream, ReceiveStream);
  74. try
  75. {
  76. SendStream?.Dispose();
  77. }
  78. catch (ObjectDisposedException)
  79. {
  80. }
  81. catch (NullReferenceException)
  82. {
  83. }
  84. finally
  85. {
  86. SendStream = null;
  87. }
  88. try
  89. {
  90. if (!oneStreamIsUsed)
  91. {
  92. ReceiveStream?.Dispose();
  93. }
  94. }
  95. catch (ObjectDisposedException)
  96. {
  97. }
  98. catch (NullReferenceException)
  99. {
  100. }
  101. finally
  102. {
  103. ReceiveStream = null;
  104. }
  105. try
  106. {
  107. _sslStream?.Dispose();
  108. }
  109. catch (ObjectDisposedException)
  110. {
  111. }
  112. catch (NullReferenceException)
  113. {
  114. }
  115. finally
  116. {
  117. _sslStream = null;
  118. }
  119. try
  120. {
  121. _socket?.Dispose();
  122. }
  123. catch (ObjectDisposedException)
  124. {
  125. }
  126. catch (NullReferenceException)
  127. {
  128. }
  129. finally
  130. {
  131. _socket = null;
  132. }
  133. }
  134. private bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
  135. {
  136. if (CustomCertificateValidationCallback != null)
  137. {
  138. return CustomCertificateValidationCallback(x509Certificate, chain, sslPolicyErrors, _options);
  139. }
  140. if (sslPolicyErrors == SslPolicyErrors.None)
  141. {
  142. return true;
  143. }
  144. if (chain.ChainStatus.Any(c => c.Status == X509ChainStatusFlags.RevocationStatusUnknown || c.Status == X509ChainStatusFlags.Revoked || c.Status == X509ChainStatusFlags.RevocationStatusUnknown))
  145. {
  146. if (!_options.TlsOptions.IgnoreCertificateRevocationErrors)
  147. {
  148. return false;
  149. }
  150. }
  151. if (chain.ChainStatus.Any(c => c.Status == X509ChainStatusFlags.PartialChain))
  152. {
  153. if (!_options.TlsOptions.IgnoreCertificateChainErrors)
  154. {
  155. return false;
  156. }
  157. }
  158. return _options.TlsOptions.AllowUntrustedCertificates;
  159. }
  160. private X509CertificateCollection LoadCertificates()
  161. {
  162. var certificates = new X509CertificateCollection();
  163. if (_options.TlsOptions.Certificates == null)
  164. {
  165. return certificates;
  166. }
  167. foreach (var certificate in _options.TlsOptions.Certificates)
  168. {
  169. certificates.Add(new X509Certificate2(certificate));
  170. }
  171. return certificates;
  172. }
  173. private void CreateStreams()
  174. {
  175. Stream stream;
  176. if (_sslStream != null)
  177. {
  178. stream = _sslStream;
  179. }
  180. else
  181. {
  182. stream = new NetworkStream(_socket, true);
  183. }
  184. #if NET452 || NET461
  185. SendStream = new BufferedStream(stream, _bufferSize);
  186. ReceiveStream = new BufferedStream(stream, _bufferSize);
  187. #else
  188. SendStream = stream;
  189. ReceiveStream = stream;
  190. #endif
  191. }
  192. }
  193. }
  194. #endif