MqttTcpServerAdapter.Uwp.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #if WINDOWS_UWP
  2. using Windows.Networking.Sockets;
  3. using MQTTnet.Adapter;
  4. using MQTTnet.Diagnostics;
  5. using MQTTnet.Formatter;
  6. using MQTTnet.Server;
  7. using System;
  8. using System.Runtime.InteropServices.WindowsRuntime;
  9. using System.Security.Cryptography.X509Certificates;
  10. using System.Threading.Tasks;
  11. namespace MQTTnet.Implementations
  12. {
  13. public sealed class MqttTcpServerAdapter : IMqttServerAdapter
  14. {
  15. readonly IMqttNetLogger _logger;
  16. IMqttServerOptions _options;
  17. StreamSocketListener _listener;
  18. public MqttTcpServerAdapter(IMqttNetLogger logger)
  19. {
  20. if (logger == null) throw new ArgumentNullException(nameof(logger));
  21. _logger = logger.CreateChildLogger(nameof(MqttTcpServerAdapter));
  22. }
  23. public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
  24. public async Task StartAsync(IMqttServerOptions options)
  25. {
  26. _options = options ?? throw new ArgumentNullException(nameof(options));
  27. if (_listener != null) throw new InvalidOperationException("Server is already started.");
  28. if (options.DefaultEndpointOptions.IsEnabled)
  29. {
  30. _listener = new StreamSocketListener();
  31. // This also affects the client sockets.
  32. _listener.Control.NoDelay = options.DefaultEndpointOptions.NoDelay;
  33. _listener.Control.KeepAlive = true;
  34. _listener.Control.QualityOfService = SocketQualityOfService.LowLatency;
  35. _listener.ConnectionReceived += OnConnectionReceivedAsync;
  36. await _listener.BindServiceNameAsync(options.DefaultEndpointOptions.Port.ToString(), SocketProtectionLevel.PlainSocket);
  37. }
  38. if (options.TlsEndpointOptions.IsEnabled)
  39. {
  40. throw new NotSupportedException("TLS servers are not supported for UWP apps.");
  41. }
  42. }
  43. public Task StopAsync()
  44. {
  45. if (_listener != null)
  46. {
  47. _listener.ConnectionReceived -= OnConnectionReceivedAsync;
  48. }
  49. return Task.FromResult(0);
  50. }
  51. public void Dispose()
  52. {
  53. _listener?.Dispose();
  54. _listener = null;
  55. }
  56. async void OnConnectionReceivedAsync(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
  57. {
  58. try
  59. {
  60. var clientHandler = ClientHandler;
  61. if (clientHandler != null)
  62. {
  63. X509Certificate2 clientCertificate = null;
  64. if (args.Socket.Control.ClientCertificate != null)
  65. {
  66. try
  67. {
  68. clientCertificate = new X509Certificate2(args.Socket.Control.ClientCertificate.GetCertificateBlob().ToArray());
  69. }
  70. catch (Exception exception)
  71. {
  72. _logger.Warning(exception, "Unable to convert UWP certificate to X509Certificate2.");
  73. }
  74. }
  75. using (var clientAdapter = new MqttChannelAdapter(new MqttTcpChannel(args.Socket, clientCertificate, _options), new MqttPacketFormatterAdapter(), _logger))
  76. {
  77. await clientHandler(clientAdapter).ConfigureAwait(false);
  78. }
  79. }
  80. }
  81. catch (Exception exception)
  82. {
  83. if (exception is ObjectDisposedException)
  84. {
  85. // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed.
  86. return;
  87. }
  88. _logger.Error(exception, "Error while handling client connection.");
  89. }
  90. finally
  91. {
  92. try
  93. {
  94. args.Socket.Dispose();
  95. }
  96. catch (Exception exception)
  97. {
  98. _logger.Error(exception, "Error while cleaning up client connection");
  99. }
  100. }
  101. }
  102. }
  103. }
  104. #endif