You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

123 lines
4.0 KiB

  1. using System;
  2. using System.IO;
  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 MQTTnet.Core.Channel;
  9. using MQTTnet.Core.Client;
  10. using MQTTnet.Core.Exceptions;
  11. namespace MQTTnet
  12. {
  13. /// <summary>
  14. /// Describes an SSL channel to a client.
  15. /// </summary>
  16. public class MqttServerSslChannel : IMqttCommunicationChannel, IDisposable
  17. {
  18. private readonly Socket _socket;
  19. private SslStream _sslStream;
  20. private X509Certificate2 _cert;
  21. /// <summary>
  22. /// Creates a new <see cref="MqttClientSslChannel"/> with a predefined <paramref name="socket"/>.
  23. /// </summary>
  24. /// <param name="socket">The client socket.</param>
  25. /// <param name="cert">The X509 certificate used to authenticate as a server.</param>
  26. public MqttServerSslChannel(Socket socket, X509Certificate2 cert)
  27. {
  28. _socket = socket ?? throw new ArgumentNullException(nameof(socket));
  29. _cert = cert ?? throw new ArgumentNullException(nameof(cert));
  30. if (!_socket.Connected)
  31. return;
  32. NetworkStream ns = new NetworkStream(_socket, true);
  33. _sslStream = new SslStream(ns);
  34. }
  35. public async Task Authenticate()
  36. {
  37. await _sslStream.AuthenticateAsServerAsync(_cert, false, SslProtocols.Tls12, false);
  38. }
  39. /// <summary>
  40. /// Asynchronously connects to the client described in the <see cref="MqttClientOptions"/>.
  41. /// </summary>
  42. /// <param name="options">The <see cref="MqttClientOptions"/> describing the connection.</param>
  43. public Task ConnectAsync(MqttClientOptions options)
  44. {
  45. try
  46. {
  47. return Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, options.Server, options.Port,
  48. null);
  49. }
  50. catch (SocketException exception)
  51. {
  52. throw new MqttCommunicationException(exception);
  53. }
  54. }
  55. /// <summary>
  56. /// Asynchronously disconnects the client from the server.
  57. /// </summary>
  58. public Task DisconnectAsync()
  59. {
  60. try
  61. {
  62. return Task.Factory.FromAsync(_socket.BeginDisconnect, _socket.EndDisconnect, true, null);
  63. }
  64. catch (SocketException exception)
  65. {
  66. throw new MqttCommunicationException(exception);
  67. }
  68. }
  69. /// <summary>
  70. /// Asynchronously writes a sequence of bytes to the socket.
  71. /// </summary>
  72. /// <param name="buffer">The buffer to write data from.</param>
  73. public Task WriteAsync(byte[] buffer)
  74. {
  75. if (buffer == null)
  76. throw new ArgumentNullException(nameof(buffer));
  77. try
  78. {
  79. return _sslStream.WriteAsync(buffer, 0, buffer.Length);
  80. }
  81. catch (Exception ex)
  82. when (ex is SocketException || ex is IOException)
  83. {
  84. throw new MqttCommunicationException(ex);
  85. }
  86. }
  87. /// <summary>
  88. /// Asynchronously reads a sequence of bytes from the socket.
  89. /// </summary>
  90. /// <param name="buffer">The buffer to write the data into.</param>
  91. public Task ReadAsync(byte[] buffer)
  92. {
  93. try
  94. {
  95. return _sslStream.ReadAsync(buffer, 0, buffer.Length);
  96. }
  97. catch (Exception ex)
  98. when (ex is SocketException || ex is IOException)
  99. {
  100. throw new MqttCommunicationException(ex);
  101. }
  102. }
  103. /// <summary>
  104. /// Releases all resources used by the <see cref="MqttClientSslChannel"/>.
  105. /// </summary>
  106. public void Dispose()
  107. {
  108. _sslStream?.Dispose();
  109. _socket?.Dispose();
  110. }
  111. }
  112. }