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.
 
 
 
 

179 líneas
5.4 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 System.Threading;
  11. using MQTTnet.Channel;
  12. using MQTTnet.Client;
  13. namespace MQTTnet.Implementations
  14. {
  15. public sealed class MqttTcpChannel : IMqttChannel
  16. {
  17. private readonly MqttClientTcpOptions _options;
  18. private Socket _socket;
  19. private Stream _stream;
  20. /// <summary>
  21. /// called on client sockets are created in connect
  22. /// </summary>
  23. public MqttTcpChannel(MqttClientTcpOptions options)
  24. {
  25. _options = options ?? throw new ArgumentNullException(nameof(options));
  26. }
  27. /// <summary>
  28. /// called on server, sockets are passed in
  29. /// connect will not be called
  30. /// </summary>
  31. public MqttTcpChannel(Socket socket, SslStream sslStream)
  32. {
  33. _socket = socket ?? throw new ArgumentNullException(nameof(socket));
  34. CreateStream(sslStream);
  35. }
  36. public static Func<X509Certificate, X509Chain, SslPolicyErrors, MqttClientTcpOptions, bool> CustomCertificateValidationCallback { get; set; }
  37. public string Endpoint => _socket?.RemoteEndPoint?.ToString();
  38. public async Task ConnectAsync(CancellationToken cancellationToken)
  39. {
  40. if (_socket == null)
  41. {
  42. _socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true };
  43. }
  44. #if NET452 || NET461
  45. await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, _options.Server, _options.GetPort(), null).ConfigureAwait(false);
  46. #else
  47. await _socket.ConnectAsync(_options.Server, _options.GetPort()).ConfigureAwait(false);
  48. #endif
  49. SslStream sslStream = null;
  50. if (_options.TlsOptions.UseTls)
  51. {
  52. sslStream = new SslStream(new NetworkStream(_socket, true), false, InternalUserCertificateValidationCallback);
  53. await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), SslProtocols.Tls12, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false);
  54. }
  55. CreateStream(sslStream);
  56. }
  57. public Task DisconnectAsync()
  58. {
  59. Dispose();
  60. return Task.FromResult(0);
  61. }
  62. public Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  63. {
  64. return _stream.ReadAsync(buffer, offset, count, cancellationToken);
  65. }
  66. public Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
  67. {
  68. return _stream.WriteAsync(buffer, offset, count, cancellationToken);
  69. }
  70. public void Dispose()
  71. {
  72. try
  73. {
  74. _stream?.Dispose();
  75. }
  76. catch (ObjectDisposedException)
  77. {
  78. }
  79. catch (NullReferenceException)
  80. {
  81. }
  82. finally
  83. {
  84. _stream = null;
  85. }
  86. try
  87. {
  88. _socket?.Dispose();
  89. }
  90. catch (ObjectDisposedException)
  91. {
  92. }
  93. catch (NullReferenceException)
  94. {
  95. }
  96. finally
  97. {
  98. _socket = null;
  99. }
  100. }
  101. private bool InternalUserCertificateValidationCallback(object sender, X509Certificate x509Certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
  102. {
  103. if (CustomCertificateValidationCallback != null)
  104. {
  105. return CustomCertificateValidationCallback(x509Certificate, chain, sslPolicyErrors, _options);
  106. }
  107. if (sslPolicyErrors == SslPolicyErrors.None)
  108. {
  109. return true;
  110. }
  111. if (chain.ChainStatus.Any(c => c.Status == X509ChainStatusFlags.RevocationStatusUnknown || c.Status == X509ChainStatusFlags.Revoked || c.Status == X509ChainStatusFlags.RevocationStatusUnknown))
  112. {
  113. if (!_options.TlsOptions.IgnoreCertificateRevocationErrors)
  114. {
  115. return false;
  116. }
  117. }
  118. if (chain.ChainStatus.Any(c => c.Status == X509ChainStatusFlags.PartialChain))
  119. {
  120. if (!_options.TlsOptions.IgnoreCertificateChainErrors)
  121. {
  122. return false;
  123. }
  124. }
  125. return _options.TlsOptions.AllowUntrustedCertificates;
  126. }
  127. private X509CertificateCollection LoadCertificates()
  128. {
  129. var certificates = new X509CertificateCollection();
  130. if (_options.TlsOptions.Certificates == null)
  131. {
  132. return certificates;
  133. }
  134. foreach (var certificate in _options.TlsOptions.Certificates)
  135. {
  136. certificates.Add(new X509Certificate2(certificate));
  137. }
  138. return certificates;
  139. }
  140. private void CreateStream(Stream stream)
  141. {
  142. if (stream != null)
  143. {
  144. _stream = stream;
  145. }
  146. else
  147. {
  148. _stream = new NetworkStream(_socket, true);
  149. }
  150. }
  151. }
  152. }
  153. #endif