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.
 
 
 
 

176 líneas
5.2 KiB

  1. #if WINDOWS_UWP
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Linq;
  6. using System.Runtime.InteropServices.WindowsRuntime;
  7. using System.Threading.Tasks;
  8. using Windows.Networking;
  9. using Windows.Networking.Sockets;
  10. using Windows.Security.Cryptography.Certificates;
  11. using MQTTnet.Channel;
  12. using MQTTnet.Client;
  13. namespace MQTTnet.Implementations
  14. {
  15. public sealed class MqttTcpChannel : IMqttChannel
  16. {
  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. private readonly MqttClientTcpOptions _options;
  22. private StreamSocket _socket;
  23. public MqttTcpChannel(MqttClientTcpOptions options)
  24. {
  25. _options = options ?? throw new ArgumentNullException(nameof(options));
  26. _bufferSize = _options.BufferSize;
  27. }
  28. public MqttTcpChannel(StreamSocket socket)
  29. {
  30. _socket = socket ?? throw new ArgumentNullException(nameof(socket));
  31. CreateStreams();
  32. }
  33. public Stream SendStream { get; private set; }
  34. public Stream ReceiveStream { get; private set; }
  35. public static Func<MqttClientTcpOptions, IEnumerable<ChainValidationResult>> CustomIgnorableServerCertificateErrorsResolver { get; set; }
  36. public async Task ConnectAsync()
  37. {
  38. if (_socket == null)
  39. {
  40. _socket = new StreamSocket();
  41. }
  42. if (!_options.TlsOptions.UseTls)
  43. {
  44. await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString());
  45. }
  46. else
  47. {
  48. _socket.Control.ClientCertificate = LoadCertificate(_options);
  49. foreach (var ignorableChainValidationResult in ResolveIgnorableServerCertificateErrors())
  50. {
  51. _socket.Control.IgnorableServerCertificateErrors.Add(ignorableChainValidationResult);
  52. }
  53. await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString(), SocketProtectionLevel.Tls12);
  54. }
  55. CreateStreams();
  56. }
  57. public Task DisconnectAsync()
  58. {
  59. Dispose();
  60. return Task.FromResult(0);
  61. }
  62. public void Dispose()
  63. {
  64. try
  65. {
  66. SendStream?.Dispose();
  67. }
  68. catch (ObjectDisposedException)
  69. {
  70. }
  71. catch (NullReferenceException)
  72. {
  73. }
  74. finally
  75. {
  76. SendStream = null;
  77. }
  78. try
  79. {
  80. ReceiveStream?.Dispose();
  81. }
  82. catch (ObjectDisposedException)
  83. {
  84. }
  85. catch (NullReferenceException)
  86. {
  87. }
  88. finally
  89. {
  90. ReceiveStream = null;
  91. }
  92. try
  93. {
  94. _socket?.Dispose();
  95. }
  96. catch (ObjectDisposedException)
  97. {
  98. }
  99. catch (NullReferenceException)
  100. {
  101. }
  102. finally
  103. {
  104. _socket = null;
  105. }
  106. }
  107. private void CreateStreams()
  108. {
  109. SendStream = _socket.OutputStream.AsStreamForWrite(_bufferSize);
  110. ReceiveStream = _socket.InputStream.AsStreamForRead(_bufferSize);
  111. }
  112. private static Certificate LoadCertificate(MqttClientTcpOptions options)
  113. {
  114. if (options.TlsOptions.Certificates == null || !options.TlsOptions.Certificates.Any())
  115. {
  116. return null;
  117. }
  118. if (options.TlsOptions.Certificates.Count > 1)
  119. {
  120. throw new NotSupportedException("Only one client certificate is supported for UWP.");
  121. }
  122. return new Certificate(options.TlsOptions.Certificates.First().AsBuffer());
  123. }
  124. private IEnumerable<ChainValidationResult> ResolveIgnorableServerCertificateErrors()
  125. {
  126. if (CustomIgnorableServerCertificateErrorsResolver != null)
  127. {
  128. return CustomIgnorableServerCertificateErrorsResolver(_options);
  129. }
  130. var result = new List<ChainValidationResult>();
  131. if (_options.TlsOptions.IgnoreCertificateRevocationErrors)
  132. {
  133. result.Add(ChainValidationResult.RevocationInformationMissing);
  134. //_socket.Control.IgnorableServerCertificateErrors.Add(ChainValidationResult.Revoked); Not supported.
  135. result.Add(ChainValidationResult.RevocationFailure);
  136. }
  137. if (_options.TlsOptions.IgnoreCertificateChainErrors)
  138. {
  139. result.Add(ChainValidationResult.IncompleteChain);
  140. }
  141. if (_options.TlsOptions.AllowUntrustedCertificates)
  142. {
  143. result.Add(ChainValidationResult.Untrusted);
  144. }
  145. return result;
  146. }
  147. }
  148. }
  149. #endif