diff --git a/.gitignore b/.gitignore
index 93a9b60..bc1ad4a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -292,3 +292,5 @@ __pycache__/
*.map
/Tests/MQTTnet.TestApp.NetCore/RetainedMessages.json
+
+Build/NuGet/
diff --git a/Build/MQTTnet.nuspec b/Build/MQTTnet.nuspec
index c9d4016..6aafdc6 100644
--- a/Build/MQTTnet.nuspec
+++ b/Build/MQTTnet.nuspec
@@ -11,7 +11,16 @@
false
MQTTnet is a high performance .NET library for MQTT based communication. It provides a MQTT client and a MQTT server (broker) and supports v3.1.0, v3.1.1 and v5.0.0 of the MQTT protocol.
-* [Server] Moved new socket options to TCP options to avoid incompatibility with Linux hosts.
+* [Core] Nuget packages with symbols are now also published to improve debugging.
+* [Core] Improve task handling (thanks to @mwinterb)
+* [ManagedClient] Fix a race condition in the message storage (thanks to @PaulFake).
+* [Server] Added items dictionary to client session in order to share data across interceptors as along as the session exists.
+* [Server] Exposed CONNECT packet properties in Application Message and Subscription interceptor.
+* [Server] Fixed: Sending Large packets with AspnetCore based connection throws System.ArgumentException.
+* [Server] Fixed wrong usage of socket option _NoDelay_.
+* [Server] Added remote certificate validation callback (thanks to @rudacs).
+* [Server] Add support for certificate passwords (thanks to @cslutgen).
+* [MQTTnet.Server] Added REST API for publishing basic messages.
Copyright Christian Kratky 2016-2019
MQTT Message Queue Telemetry Transport MQTTClient MQTTServer Server MQTTBroker Broker NETStandard IoT InternetOfThings Messaging Hardware Arduino Sensor Actuator M2M ESP Smart Home Cities Automation Xamarin
diff --git a/Build/build.ps1 b/Build/build.ps1
index f5f9975..33f2767 100644
--- a/Build/build.ps1
+++ b/Build/build.ps1
@@ -59,12 +59,12 @@ Copy-Item MQTTnet.Extensions.WebSocket4Net.nuspec -Destination MQTTnet.Extension
(Get-Content MQTTnet.Extensions.WebSocket4Net.nuspec) -replace '\$nugetVersion', $nugetVersion | Set-Content MQTTnet.Extensions.WebSocket4Net.nuspec
New-Item -ItemType Directory -Force -Path .\NuGet
-.\nuget.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
-.\nuget.exe pack MQTTnet.NETStandard.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
-.\nuget.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
-.\nuget.exe pack MQTTnet.Extensions.Rpc.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
-.\nuget.exe pack MQTTnet.Extensions.ManagedClient.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
-.\nuget.exe pack MQTTnet.Extensions.WebSocket4Net.nuspec -Verbosity detailed -Symbols -OutputDir "NuGet" -Version $nugetVersion
+.\nuget.exe pack MQTTnet.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
+.\nuget.exe pack MQTTnet.NETStandard.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
+.\nuget.exe pack MQTTnet.AspNetCore.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
+.\nuget.exe pack MQTTnet.Extensions.Rpc.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
+.\nuget.exe pack MQTTnet.Extensions.ManagedClient.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
+.\nuget.exe pack MQTTnet.Extensions.WebSocket4Net.nuspec -Verbosity detailed -Symbols -SymbolPackageFormat snupkg -OutputDir "NuGet" -Version $nugetVersion
Move-Item MQTTnet.AspNetCore.nuspec.old -Destination MQTTnet.AspNetCore.nuspec -Force
Move-Item MQTTnet.Extensions.Rpc.nuspec.old -Destination MQTTnet.Extensions.Rpc.nuspec -Force
diff --git a/Build/upload.ps1 b/Build/upload.ps1
index adb7c6d..794fe87 100644
--- a/Build/upload.ps1
+++ b/Build/upload.ps1
@@ -7,7 +7,7 @@ foreach ($file in $files)
{
Write-Host "Uploading: " $file
- .\nuget.exe push $file.Fullname $apiKey -NoSymbols -Source https://api.nuget.org/v3/index.json
+ .\nuget.exe push $file.Fullname $apiKey -Source https://api.nuget.org/v3/index.json
}
Remove-Item "nuget.exe" -Force -Recurse -ErrorAction SilentlyContinue
\ No newline at end of file
diff --git a/Source/MQTTnet.AspnetCore/MqttConnectionContext.cs b/Source/MQTTnet.AspnetCore/MqttConnectionContext.cs
index f50d85d..2aa9842 100644
--- a/Source/MQTTnet.AspnetCore/MqttConnectionContext.cs
+++ b/Source/MQTTnet.AspnetCore/MqttConnectionContext.cs
@@ -162,11 +162,12 @@ namespace MQTTnet.AspNetCore
var buffer = formatter.Encode(packet);
var msg = buffer.AsMemory();
var output = _output;
- msg.CopyTo(output.GetMemory(msg.Length));
- BytesSent += msg.Length;
+ var result = await output.WriteAsync(msg, cancellationToken).ConfigureAwait(false);
+ if (result.IsCompleted)
+ {
+ BytesSent += msg.Length;
+ }
PacketFormatterAdapter.FreeBuffer();
- output.Advance(msg.Length);
- await output.FlushAsync().ConfigureAwait(false);
}
finally
{
diff --git a/Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs b/Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs
index 74d148d..f53a8dd 100644
--- a/Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs
+++ b/Source/MQTTnet.Extensions.ManagedClient/ManagedMqttClient.cs
@@ -24,6 +24,8 @@ namespace MQTTnet.Extensions.ManagedClient
private readonly IMqttClient _mqttClient;
private readonly IMqttNetChildLogger _logger;
+
+ private readonly AsyncLock _messageQueueLock = new AsyncLock();
private CancellationTokenSource _connectionCancellationToken;
private CancellationTokenSource _publishingCancellationToken;
@@ -147,7 +149,7 @@ namespace MQTTnet.Extensions.ManagedClient
try
{
- lock (_messageQueue)
+ using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false))
{
if (_messageQueue.Count >= Options.MaxPendingMessages)
{
@@ -167,6 +169,16 @@ namespace MQTTnet.Extensions.ManagedClient
}
_messageQueue.Enqueue(applicationMessage);
+
+ if (_storageManager != null)
+ {
+ if (removedMessage != null)
+ {
+ await _storageManager.RemoveAsync(removedMessage).ConfigureAwait(false);
+ }
+
+ await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false);
+ }
}
}
finally
@@ -181,16 +193,6 @@ namespace MQTTnet.Extensions.ManagedClient
}
}
-
- if (_storageManager != null)
- {
- if (removedMessage != null)
- {
- await _storageManager.RemoveAsync(removedMessage).ConfigureAwait(false);
- }
-
- await _storageManager.AddAsync(applicationMessage).ConfigureAwait(false);
- }
}
public Task SubscribeAsync(IEnumerable topicFilters)
@@ -362,7 +364,7 @@ namespace MQTTnet.Extensions.ManagedClient
}
catch (Exception exception)
{
- _logger.Error(exception, "Unhandled exception while publishing queued application messages.");
+ _logger.Error(exception, "Error while publishing queued application messages.");
}
finally
{
@@ -377,7 +379,7 @@ namespace MQTTnet.Extensions.ManagedClient
{
await _mqttClient.PublishAsync(message.ApplicationMessage).ConfigureAwait(false);
- lock (_messageQueue) //lock to avoid conflict with this.PublishAsync
+ using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false)) //lock to avoid conflict with this.PublishAsync
{
// While publishing this message, this.PublishAsync could have booted this
// message off the queue to make room for another (when using a cap
@@ -386,11 +388,11 @@ namespace MQTTnet.Extensions.ManagedClient
// it from the queue. If not, that means this.PublishAsync has already
// removed it, in which case we don't want to do anything.
_messageQueue.RemoveFirst(i => i.Id.Equals(message.Id));
- }
-
- if (_storageManager != null)
- {
- await _storageManager.RemoveAsync(message).ConfigureAwait(false);
+
+ if (_storageManager != null)
+ {
+ await _storageManager.RemoveAsync(message).ConfigureAwait(false);
+ }
}
}
catch (MqttCommunicationException exception)
@@ -408,21 +410,21 @@ namespace MQTTnet.Extensions.ManagedClient
//contradict the expected behavior of QoS 1 and 2, that's also true
//for the usage of a message queue cap, so it's still consistent
//with prior behavior in that way.
- lock (_messageQueue) //lock to avoid conflict with this.PublishAsync
+ using (await _messageQueueLock.WaitAsync(CancellationToken.None).ConfigureAwait(false)) //lock to avoid conflict with this.PublishAsync
{
_messageQueue.RemoveFirst(i => i.Id.Equals(message.Id));
- }
-
- if (_storageManager != null)
- {
- await _storageManager.RemoveAsync(message).ConfigureAwait(false);
+
+ if (_storageManager != null)
+ {
+ await _storageManager.RemoveAsync(message).ConfigureAwait(false);
+ }
}
}
}
catch (Exception exception)
{
transmitException = exception;
- _logger.Error(exception, $"Unhandled exception while publishing application message ({message.Id}).");
+ _logger.Error(exception, $"Error while publishing application message ({message.Id}).");
}
finally
{
@@ -533,4 +535,4 @@ namespace MQTTnet.Extensions.ManagedClient
_connectionCancellationToken = null;
}
}
-}
\ No newline at end of file
+}
diff --git a/Source/MQTTnet.Server/Controllers/ClientsController.cs b/Source/MQTTnet.Server/Controllers/ClientsController.cs
index 6898375..bd9795a 100644
--- a/Source/MQTTnet.Server/Controllers/ClientsController.cs
+++ b/Source/MQTTnet.Server/Controllers/ClientsController.cs
@@ -13,7 +13,7 @@ namespace MQTTnet.Server.Controllers
{
[Authorize]
[ApiController]
- public class ClientsController : ControllerBase
+ public class ClientsController : Controller
{
private readonly MqttServerService _mqttServerService;
diff --git a/Source/MQTTnet.Server/Controllers/MessagesController.cs b/Source/MQTTnet.Server/Controllers/MessagesController.cs
new file mode 100644
index 0000000..6bd00e7
--- /dev/null
+++ b/Source/MQTTnet.Server/Controllers/MessagesController.cs
@@ -0,0 +1,51 @@
+using System;
+using System.IO;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using MQTTnet.Protocol;
+using MQTTnet.Server.Mqtt;
+
+namespace MQTTnet.Server.Controllers
+{
+ [Authorize]
+ [ApiController]
+ public class MessagesController : Controller
+ {
+ private readonly MqttServerService _mqttServerService;
+
+ public MessagesController(MqttServerService mqttServerService)
+ {
+ _mqttServerService = mqttServerService ?? throw new ArgumentNullException(nameof(mqttServerService));
+ }
+
+ [Route("api/v1/messages")]
+ [HttpPost]
+ public async Task PostMessage(MqttApplicationMessage message)
+ {
+ await _mqttServerService.PublishAsync(message);
+ return Ok();
+ }
+
+ [Route("api/v1/messages/{*topic}")]
+ [HttpPost]
+ public async Task PostMessage(string topic, int qosLevel = 0)
+ {
+ byte[] payload;
+
+ using (var memoryStream = new MemoryStream())
+ {
+ await HttpContext.Request.Body.CopyToAsync(memoryStream);
+ payload = memoryStream.ToArray();
+ }
+
+ var message = new MqttApplicationMessageBuilder()
+ .WithTopic(topic)
+ .WithPayload(payload)
+ .WithQualityOfServiceLevel((MqttQualityOfServiceLevel)qosLevel)
+ .Build();
+
+ return await PostMessage(message);
+ }
+ }
+}
diff --git a/Source/MQTTnet.Server/Controllers/RetainedApplicationMessagesController.cs b/Source/MQTTnet.Server/Controllers/RetainedApplicationMessagesController.cs
index 9c9f273..030d141 100644
--- a/Source/MQTTnet.Server/Controllers/RetainedApplicationMessagesController.cs
+++ b/Source/MQTTnet.Server/Controllers/RetainedApplicationMessagesController.cs
@@ -12,7 +12,7 @@ namespace MQTTnet.Server.Controllers
{
[Authorize]
[ApiController]
- public class RetainedApplicationMessagesController : ControllerBase
+ public class RetainedApplicationMessagesController : Controller
{
private readonly MqttServerService _mqttServerService;
diff --git a/Source/MQTTnet.Server/Controllers/ServerController.cs b/Source/MQTTnet.Server/Controllers/ServerController.cs
new file mode 100644
index 0000000..cf53bba
--- /dev/null
+++ b/Source/MQTTnet.Server/Controllers/ServerController.cs
@@ -0,0 +1,18 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using System.Reflection;
+
+namespace MQTTnet.Server.Controllers
+{
+ [Authorize]
+ [ApiController]
+ public class ServerController : Controller
+ {
+ [Route("api/v1/server/version")]
+ [HttpGet]
+ public ActionResult GetVersion()
+ {
+ return Assembly.GetExecutingAssembly().GetCustomAttribute().InformationalVersion;
+ }
+ }
+}
diff --git a/Source/MQTTnet.Server/Controllers/SessionsController.cs b/Source/MQTTnet.Server/Controllers/SessionsController.cs
index 463c004..5fd0638 100644
--- a/Source/MQTTnet.Server/Controllers/SessionsController.cs
+++ b/Source/MQTTnet.Server/Controllers/SessionsController.cs
@@ -13,7 +13,7 @@ namespace MQTTnet.Server.Controllers
{
[Authorize]
[ApiController]
- public class SessionsController : ControllerBase
+ public class SessionsController : Controller
{
private readonly MqttServerService _mqttServerService;
diff --git a/Source/MQTTnet.Server/Mqtt/MqttApplicationMessageInterceptor.cs b/Source/MQTTnet.Server/Mqtt/MqttApplicationMessageInterceptor.cs
index c5f3afd..00eb0e7 100644
--- a/Source/MQTTnet.Server/Mqtt/MqttApplicationMessageInterceptor.cs
+++ b/Source/MQTTnet.Server/Mqtt/MqttApplicationMessageInterceptor.cs
@@ -22,14 +22,17 @@ namespace MQTTnet.Server.Mqtt
{
try
{
+ var sessionItems = (PythonDictionary)context.SessionItems[MqttServerConnectionValidator.WrappedSessionItemsKey];
+
var pythonContext = new PythonDictionary
{
+ { "client_id", context.ClientId },
+ { "session_items", sessionItems },
+ { "retain", context.ApplicationMessage.Retain },
{ "accept_publish", context.AcceptPublish },
{ "close_connection", context.CloseConnection },
- { "client_id", context.ClientId },
{ "topic", context.ApplicationMessage.Topic },
- { "qos", (int)context.ApplicationMessage.QualityOfServiceLevel },
- { "retain", context.ApplicationMessage.Retain }
+ { "qos", (int)context.ApplicationMessage.QualityOfServiceLevel }
};
_pythonScriptHostService.InvokeOptionalFunction("on_intercept_application_message", pythonContext);
diff --git a/Source/MQTTnet.Server/Mqtt/MqttServerConnectionValidator.cs b/Source/MQTTnet.Server/Mqtt/MqttServerConnectionValidator.cs
index 3b1a2fc..d002842 100644
--- a/Source/MQTTnet.Server/Mqtt/MqttServerConnectionValidator.cs
+++ b/Source/MQTTnet.Server/Mqtt/MqttServerConnectionValidator.cs
@@ -9,6 +9,8 @@ namespace MQTTnet.Server.Mqtt
{
public class MqttServerConnectionValidator : IMqttServerConnectionValidator
{
+ public const string WrappedSessionItemsKey = "WRAPPED_ITEMS";
+
private readonly PythonScriptHostService _pythonScriptHostService;
private readonly ILogger _logger;
@@ -22,6 +24,8 @@ namespace MQTTnet.Server.Mqtt
{
try
{
+ var sessionItems = new PythonDictionary();
+
var pythonContext = new PythonDictionary
{
{ "endpoint", context.Endpoint },
@@ -33,6 +37,7 @@ namespace MQTTnet.Server.Mqtt
{ "clean_session", context.CleanSession},
{ "authentication_method", context.AuthenticationMethod},
{ "authentication_data", new Bytes(context.AuthenticationData ?? new byte[0]) },
+ { "session_items", sessionItems },
{ "result", PythonConvert.Pythonfy(context.ReasonCode) }
};
@@ -40,6 +45,8 @@ namespace MQTTnet.Server.Mqtt
_pythonScriptHostService.InvokeOptionalFunction("on_validate_client_connection", pythonContext);
context.ReasonCode = PythonConvert.ParseEnum((string)pythonContext["result"]);
+
+ context.SessionItems[WrappedSessionItemsKey] = sessionItems;
}
catch (Exception exception)
{
diff --git a/Source/MQTTnet.Server/Mqtt/MqttSubscriptionInterceptor.cs b/Source/MQTTnet.Server/Mqtt/MqttSubscriptionInterceptor.cs
index 2d37f74..ba99e9f 100644
--- a/Source/MQTTnet.Server/Mqtt/MqttSubscriptionInterceptor.cs
+++ b/Source/MQTTnet.Server/Mqtt/MqttSubscriptionInterceptor.cs
@@ -21,14 +21,16 @@ namespace MQTTnet.Server.Mqtt
{
try
{
+ var sessionItems = (PythonDictionary)context.SessionItems[MqttServerConnectionValidator.WrappedSessionItemsKey];
+
var pythonContext = new PythonDictionary
{
- { "accept_subscription", context.AcceptSubscription },
- { "close_connection", context.CloseConnection },
-
{ "client_id", context.ClientId },
+ { "session_items", sessionItems },
{ "topic", context.TopicFilter.Topic },
- { "qos", (int)context.TopicFilter.QualityOfServiceLevel }
+ { "qos", (int)context.TopicFilter.QualityOfServiceLevel },
+ { "accept_subscription", context.AcceptSubscription },
+ { "close_connection", context.CloseConnection }
};
_pythonScriptHostService.InvokeOptionalFunction("on_intercept_subscription", pythonContext);
diff --git a/Source/MQTTnet/Client/MqttClient.cs b/Source/MQTTnet/Client/MqttClient.cs
index e29e9d0..27b56ff 100644
--- a/Source/MQTTnet/Client/MqttClient.cs
+++ b/Source/MQTTnet/Client/MqttClient.cs
@@ -257,12 +257,12 @@ namespace MQTTnet.Client
{
var clientWasConnected = IsConnected;
- InitiateDisconnect();
-
- IsConnected = false;
+ TryInitiateDisconnect();
try
{
+ IsConnected = false;
+
if (_adapter != null)
{
_logger.Verbose("Disconnecting [Timeout={0}]", Options.CommunicationTimeout);
@@ -295,7 +295,7 @@ namespace MQTTnet.Client
}
}
- private void InitiateDisconnect()
+ private void TryInitiateDisconnect()
{
lock (_disconnectLock)
{
diff --git a/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs b/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs
index a7aefd1..65a1ec9 100644
--- a/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs
+++ b/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs
@@ -139,6 +139,13 @@ namespace MQTTnet.Client.Options
return this;
}
+ public MqttClientOptionsBuilder WithCredentials(IMqttClientCredentials credentials)
+ {
+ _options.Credentials = credentials;
+
+ return this;
+ }
+
public MqttClientOptionsBuilder WithExtendedAuthenticationExchangeHandler(IMqttExtendedAuthenticationExchangeHandler handler)
{
_options.ExtendedAuthenticationExchangeHandler = handler;
diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs
index 63adf55..12fd2bb 100644
--- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs
+++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs
@@ -84,9 +84,9 @@ namespace MQTTnet.Implementations
if (_options.TlsOptions.UseTls)
{
var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback);
- await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false);
-
_stream = sslStream;
+
+ await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, _options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false);
}
else
{
diff --git a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs
index 0e28ad0..e3dcab8 100644
--- a/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs
+++ b/Source/MQTTnet/Implementations/MqttTcpServerAdapter.cs
@@ -48,7 +48,7 @@ namespace MQTTnet.Implementations
throw new ArgumentException("TLS certificate is not set.");
}
- var tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate);
+ var tlsCertificate = new X509Certificate2(options.TlsEndpointOptions.Certificate, options.TlsEndpointOptions.CertificateCredentials.Password);
if (!tlsCertificate.HasPrivateKey)
{
throw new InvalidOperationException("The certificate for TLS encryption must contain the private key.");
diff --git a/Source/MQTTnet/Implementations/MqttTcpServerListener.cs b/Source/MQTTnet/Implementations/MqttTcpServerListener.cs
index 62eea00..d57888e 100644
--- a/Source/MQTTnet/Implementations/MqttTcpServerListener.cs
+++ b/Source/MQTTnet/Implementations/MqttTcpServerListener.cs
@@ -61,6 +61,8 @@ namespace MQTTnet.Implementations
_socket = new Socket(_addressFamily, SocketType.Stream, ProtocolType.Tcp);
+ // Usage of socket options is described here: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.setsocketoption?view=netcore-2.2
+
if (_options.ReuseAddress)
{
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
@@ -68,7 +70,7 @@ namespace MQTTnet.Implementations
if (_options.NoDelay)
{
- _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, true);
+ _socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
}
_socket.Bind(_localEndPoint);
@@ -160,7 +162,7 @@ namespace MQTTnet.Implementations
if (_tlsCertificate != null)
{
- var sslStream = new SslStream(stream, false);
+ var sslStream = new SslStream(stream, false, _tlsOptions.RemoteCertificateValidationCallback);
await sslStream.AuthenticateAsServerAsync(
_tlsCertificate,
@@ -171,6 +173,11 @@ namespace MQTTnet.Implementations
stream = sslStream;
clientCertificate = sslStream.RemoteCertificate as X509Certificate2;
+
+ if (clientCertificate == null && sslStream.RemoteCertificate != null)
+ {
+ clientCertificate = new X509Certificate2(sslStream.RemoteCertificate.Export(X509ContentType.Cert));
+ }
}
var clientHandler = ClientHandler;
diff --git a/Source/MQTTnet/Internal/AsyncLock.cs b/Source/MQTTnet/Internal/AsyncLock.cs
index 9b7eefd..17d7404 100644
--- a/Source/MQTTnet/Internal/AsyncLock.cs
+++ b/Source/MQTTnet/Internal/AsyncLock.cs
@@ -23,7 +23,7 @@ namespace MQTTnet.Internal
public Task WaitAsync(CancellationToken cancellationToken)
{
var task = _semaphore.WaitAsync(cancellationToken);
- if (task.IsCompleted)
+ if (task.Status == TaskStatus.RanToCompletion)
{
return _releaser;
}
diff --git a/Source/MQTTnet/MQTTnet.csproj b/Source/MQTTnet/MQTTnet.csproj
index 5e0251d..61ca517 100644
--- a/Source/MQTTnet/MQTTnet.csproj
+++ b/Source/MQTTnet/MQTTnet.csproj
@@ -41,13 +41,13 @@
RELEASE;NETSTANDARD1_3
-
+
-
+
diff --git a/Source/MQTTnet/Server/IMqttServerCredentials.cs b/Source/MQTTnet/Server/IMqttServerCredentials.cs
new file mode 100644
index 0000000..5e75be9
--- /dev/null
+++ b/Source/MQTTnet/Server/IMqttServerCredentials.cs
@@ -0,0 +1,6 @@
+using System;
+
+public interface IMqttServerCredentials
+{
+ String Password { get; }
+}
diff --git a/Source/MQTTnet/Server/IMqttServerOptions.cs b/Source/MQTTnet/Server/IMqttServerOptions.cs
index 3a24289..7c5fde4 100644
--- a/Source/MQTTnet/Server/IMqttServerOptions.cs
+++ b/Source/MQTTnet/Server/IMqttServerOptions.cs
@@ -21,6 +21,8 @@ namespace MQTTnet.Server
MqttServerTcpEndpointOptions DefaultEndpointOptions { get; }
MqttServerTlsTcpEndpointOptions TlsEndpointOptions { get; }
- IMqttServerStorage Storage { get; }
+ IMqttServerStorage Storage { get; }
+
+
}
}
\ No newline at end of file
diff --git a/Source/MQTTnet/Server/IMqttServerPersistedSession.cs b/Source/MQTTnet/Server/IMqttServerPersistedSession.cs
new file mode 100644
index 0000000..18f7165
--- /dev/null
+++ b/Source/MQTTnet/Server/IMqttServerPersistedSession.cs
@@ -0,0 +1,22 @@
+using System;
+using System.Collections.Generic;
+
+namespace MQTTnet.Server
+{
+ public interface IMqttServerPersistedSession
+ {
+ string ClientId { get; }
+
+ IDictionary