mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-15 00:15:15 +08:00
Compare commits
18
Commits
v3.0.3-rc3
...
v3.0.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ed8e55394 | ||
|
|
c5b6ca204d | ||
|
|
7a767c7d2f | ||
|
|
dd96cf98a8 | ||
|
|
6ee3d1640f | ||
|
|
6f8272210c | ||
|
|
ce05cc9936 | ||
|
|
985c3084a8 | ||
|
|
7b3be3a64f | ||
|
|
c50fb740fc | ||
|
|
5895a73f85 | ||
|
|
961a497798 | ||
|
|
6a90864c44 | ||
|
|
a9017b8795 | ||
|
|
f76e130283 | ||
|
|
5a48b146b4 | ||
|
|
1d1def3275 | ||
|
|
bd75a2440e |
@@ -15,6 +15,7 @@
|
||||
* [Core] Added extension method to allow usage of _WebSocket4Net_ in clients to fix issues with AWS and Xamarin.
|
||||
* [Core] Fixed usage of wrong data type for passwords (string -> byte[]).
|
||||
* [Core] Fixed an _ObjectDisposedException_ when sending data using a WebSocket channel.
|
||||
* [Core] Performance optimizations.
|
||||
* [Client] Added support for extended authentication exchange.
|
||||
* [Client] Exposed MQTTv5 CONNACK values to client.
|
||||
* [Client] Added _MqttClientSubscribeOptionsBuilder_.
|
||||
|
||||
+6
-1
@@ -90,6 +90,9 @@ If(Test-path $destination) {Remove-item $destination}
|
||||
####################################################################
|
||||
|
||||
# Create NuGet packages.
|
||||
|
||||
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe"
|
||||
|
||||
Remove-Item .\NuGet -Force -Recurse -ErrorAction SilentlyContinue
|
||||
|
||||
Copy-Item MQTTnet.AspNetCore.nuspec -Destination MQTTnet.AspNetCore.nuspec.old -Force
|
||||
@@ -112,4 +115,6 @@ New-Item -ItemType Directory -Force -Path .\NuGet
|
||||
Move-Item MQTTnet.AspNetCore.nuspec.old -Destination MQTTnet.AspNetCore.nuspec -Force
|
||||
Move-Item MQTTnet.Extensions.Rpc.nuspec.old -Destination MQTTnet.Extensions.Rpc.nuspec -Force
|
||||
Move-Item MQTTnet.Extensions.ManagedClient.nuspec.old -Destination MQTTnet.Extensions.ManagedClient.nuspec -Force
|
||||
Move-Item MQTTnet.Extensions.WebSocket4Net.nuspec.old -Destination MQTTnet.Extensions.WebSocket4Net.nuspec -Force
|
||||
Move-Item MQTTnet.Extensions.WebSocket4Net.nuspec.old -Destination MQTTnet.Extensions.WebSocket4Net.nuspec -Force
|
||||
|
||||
Remove-Item "nuget.exe" -Force -Recurse -ErrorAction SilentlyContinue
|
||||
Binary file not shown.
+5
-1
@@ -1,9 +1,13 @@
|
||||
param([string]$apiKey)
|
||||
|
||||
Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" -OutFile "nuget.exe"
|
||||
|
||||
$files = Get-ChildItem -Path ".\NuGet" -Filter "*.nupkg"
|
||||
foreach ($file in $files)
|
||||
{
|
||||
Write-Host "Uploading: " $file
|
||||
|
||||
.\nuget.exe push $file.Fullname $apiKey -NoSymbols -Source https://api.nuget.org/v3/index.json
|
||||
}
|
||||
}
|
||||
|
||||
Remove-Item "nuget.exe" -Force -Recurse -ErrorAction SilentlyContinue
|
||||
@@ -9,6 +9,7 @@ namespace MQTTnet.AspNetCore
|
||||
public class SpanBasedMqttPacketBodyReader : IMqttPacketBodyReader
|
||||
{
|
||||
private ReadOnlyMemory<byte> _buffer;
|
||||
|
||||
private int _offset;
|
||||
|
||||
public void SetBuffer(ReadOnlyMemory<byte> buffer)
|
||||
@@ -17,11 +18,11 @@ namespace MQTTnet.AspNetCore
|
||||
_offset = 0;
|
||||
}
|
||||
|
||||
public ulong Length => (ulong)_buffer.Length;
|
||||
public int Length => _buffer.Length;
|
||||
|
||||
public bool EndOfStream => _buffer.Length.Equals(_offset);
|
||||
|
||||
public ulong Offset => (ulong)_offset;
|
||||
public int Offset => _offset;
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
@@ -116,9 +117,9 @@ namespace MQTTnet.AspNetCore
|
||||
throw new MqttProtocolViolationException("Boolean values can be 0 or 1 only.");
|
||||
}
|
||||
|
||||
public void Seek(ulong position)
|
||||
public void Seek(int position)
|
||||
{
|
||||
_offset = (int)position;
|
||||
_offset = position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
private ManagedMqttClientStorageManager _storageManager;
|
||||
|
||||
private bool _disposed = false;
|
||||
private bool _disposed;
|
||||
private bool _subscriptionsNotPushed;
|
||||
|
||||
public ManagedMqttClient(IMqttClient mqttClient, IMqttNetChildLogger logger)
|
||||
@@ -102,9 +102,8 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
_connectionCancellationToken = new CancellationTokenSource();
|
||||
|
||||
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
_maintainConnectionTask = Task.Run(() => MaintainConnectionAsync(_connectionCancellationToken.Token), _connectionCancellationToken.Token);
|
||||
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
|
||||
_maintainConnectionTask.Forget(_logger);
|
||||
|
||||
_logger.Info("Started");
|
||||
}
|
||||
@@ -333,20 +332,20 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
private void PublishQueuedMessages(CancellationToken cancellationToken)
|
||||
private async Task PublishQueuedMessagesAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!cancellationToken.IsCancellationRequested && _mqttClient.IsConnected)
|
||||
{
|
||||
//Peek at the message without dequeueing in order to prevent the
|
||||
//possibility of the queue growing beyond the configured cap.
|
||||
//Previously, messages could be re-enqueued if there was an
|
||||
//exception, and this re-enqueueing did not honor the cap.
|
||||
//Furthermore, because re-enqueueing would shuffle the order
|
||||
//of the messages, the DropOldestQueuedMessage strategy would
|
||||
//be unable to know which message is actually the oldest and would
|
||||
//instead drop the first item in the queue.
|
||||
// Peek at the message without dequeueing in order to prevent the
|
||||
// possibility of the queue growing beyond the configured cap.
|
||||
// Previously, messages could be re-enqueued if there was an
|
||||
// exception, and this re-enqueueing did not honor the cap.
|
||||
// Furthermore, because re-enqueueing would shuffle the order
|
||||
// of the messages, the DropOldestQueuedMessage strategy would
|
||||
// be unable to know which message is actually the oldest and would
|
||||
// instead drop the first item in the queue.
|
||||
var message = _messageQueue.PeekAndWait();
|
||||
if (message == null)
|
||||
{
|
||||
@@ -355,7 +354,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
TryPublishQueuedMessage(message);
|
||||
await TryPublishQueuedMessageAsync(message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
@@ -371,23 +370,28 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
}
|
||||
|
||||
private void TryPublishQueuedMessage(ManagedMqttApplicationMessage message)
|
||||
private async Task TryPublishQueuedMessageAsync(ManagedMqttApplicationMessage message)
|
||||
{
|
||||
Exception transmitException = null;
|
||||
try
|
||||
{
|
||||
_mqttClient.PublishAsync(message.ApplicationMessage).GetAwaiter().GetResult();
|
||||
await _mqttClient.PublishAsync(message.ApplicationMessage).ConfigureAwait(false);
|
||||
|
||||
lock (_messageQueue) //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
|
||||
//with the DropOldestQueuedMessage strategy). If the first item
|
||||
//in the queue is equal to this message, then it's safe to remove
|
||||
//it from the queue. If not, that means this.PublishAsync has already
|
||||
//removed it, in which case we don't want to do anything.
|
||||
// While publishing this message, this.PublishAsync could have booted this
|
||||
// message off the queue to make room for another (when using a cap
|
||||
// with the DropOldestQueuedMessage strategy). If the first item
|
||||
// in the queue is equal to this message, then it's safe to remove
|
||||
// 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));
|
||||
}
|
||||
_storageManager?.RemoveAsync(message).GetAwaiter().GetResult();
|
||||
|
||||
if (_storageManager != null)
|
||||
{
|
||||
await _storageManager.RemoveAsync(message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (MqttCommunicationException exception)
|
||||
{
|
||||
@@ -408,6 +412,11 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
{
|
||||
_messageQueue.RemoveFirst(i => i.Id.Equals(message.Id));
|
||||
}
|
||||
|
||||
if (_storageManager != null)
|
||||
{
|
||||
await _storageManager.RemoveAsync(message).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
@@ -417,7 +426,12 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
}
|
||||
finally
|
||||
{
|
||||
ApplicationMessageProcessedHandler?.HandleApplicationMessageProcessedAsync(new ApplicationMessageProcessedEventArgs(message, transmitException)).GetAwaiter().GetResult();
|
||||
var eventHandler = ApplicationMessageProcessedHandler;
|
||||
if (eventHandler != null)
|
||||
{
|
||||
var eventArguments = new ApplicationMessageProcessedEventArgs(message, transmitException);
|
||||
await eventHandler.HandleApplicationMessageProcessedAsync(eventArguments).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,7 +516,7 @@ namespace MQTTnet.Extensions.ManagedClient
|
||||
var cts = new CancellationTokenSource();
|
||||
_publishingCancellationToken = cts;
|
||||
|
||||
Task.Factory.StartNew(() => PublishQueuedMessages(cts.Token), cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
|
||||
Task.Run(() => PublishQueuedMessagesAsync(cts.Token), cts.Token).Forget(_logger);
|
||||
}
|
||||
|
||||
private void StopPublishing()
|
||||
|
||||
@@ -29,10 +29,10 @@ namespace MQTTnet.Server.Mqtt
|
||||
{ "client_id", context.ClientId },
|
||||
{ "username", context.Username },
|
||||
{ "password", context.Password },
|
||||
{ "raw_password", new Bytes(context.RawPassword) },
|
||||
{ "raw_password", new Bytes(context.RawPassword ?? new byte[0]) },
|
||||
{ "clean_session", context.CleanSession},
|
||||
{ "authentication_method", context.AuthenticationMethod},
|
||||
{ "authentication_data", new Bytes(context.AuthenticationData)},
|
||||
{ "authentication_data", new Bytes(context.AuthenticationData ?? new byte[0]) },
|
||||
|
||||
{ "result", PythonConvert.Pythonfy(context.ReasonCode) }
|
||||
};
|
||||
@@ -44,6 +44,8 @@ namespace MQTTnet.Server.Mqtt
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogError(exception, "Error while validating client connection.");
|
||||
|
||||
context.ReasonCode = MqttConnectReasonCode.UnspecifiedError;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
|
||||
@@ -66,7 +66,10 @@ namespace MQTTnet.Server.Mqtt
|
||||
|
||||
var adapters = new List<IMqttServerAdapter>
|
||||
{
|
||||
new MqttTcpServerAdapter(mqttFactory.Logger.CreateChildLogger()),
|
||||
new MqttTcpServerAdapter(mqttFactory.Logger.CreateChildLogger())
|
||||
{
|
||||
TreatSocketOpeningErrorAsWarning = true // Opening other ports than for HTTP is not allows in Azure App Services.
|
||||
},
|
||||
_webSocketServerAdapter
|
||||
};
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
"Kestrel": {
|
||||
"EndPoints": {
|
||||
"Http": {
|
||||
"Url": "http://localhost:80"
|
||||
"Url": "http://*:80"
|
||||
},
|
||||
"Https": {
|
||||
"Url": "http://localhost:443"
|
||||
"Url": "http://*:443"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -4,9 +4,9 @@ namespace MQTTnet.Formatter
|
||||
{
|
||||
public interface IMqttPacketBodyReader
|
||||
{
|
||||
ulong Length { get; }
|
||||
int Length { get; }
|
||||
|
||||
ulong Offset { get; }
|
||||
int Offset { get; }
|
||||
|
||||
bool EndOfStream { get; }
|
||||
|
||||
@@ -26,6 +26,6 @@ namespace MQTTnet.Formatter
|
||||
|
||||
bool ReadBoolean();
|
||||
|
||||
void Seek(ulong position);
|
||||
void Seek(int position);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,52 +9,42 @@ namespace MQTTnet.Formatter
|
||||
public class MqttPacketBodyReader : IMqttPacketBodyReader
|
||||
{
|
||||
private readonly byte[] _buffer;
|
||||
private readonly ulong _initialOffset;
|
||||
private readonly ulong _length;
|
||||
private readonly int _initialOffset;
|
||||
private readonly int _length;
|
||||
|
||||
private int _offset;
|
||||
|
||||
public MqttPacketBodyReader(byte[] buffer, int offset, int length)
|
||||
: this(buffer, (ulong)offset, (ulong)length)
|
||||
{
|
||||
}
|
||||
|
||||
public MqttPacketBodyReader(byte[] buffer, ulong offset, ulong length)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_initialOffset = offset;
|
||||
Offset = offset;
|
||||
_offset = offset;
|
||||
_length = length;
|
||||
}
|
||||
|
||||
public ulong Offset { get; private set; }
|
||||
public int Offset => _offset;
|
||||
|
||||
public ulong Length => _length - Offset;
|
||||
public int Length => _length - _offset;
|
||||
|
||||
public bool EndOfStream => Offset == _length;
|
||||
public bool EndOfStream => _offset == _length;
|
||||
|
||||
public void Seek(ulong position)
|
||||
public void Seek(int position)
|
||||
{
|
||||
Offset = _initialOffset + position;
|
||||
}
|
||||
|
||||
public ArraySegment<byte> Read(uint length)
|
||||
{
|
||||
ValidateReceiveBuffer(length);
|
||||
|
||||
var buffer = new ArraySegment<byte>(_buffer, (int)Offset, (int)length);
|
||||
Offset += length;
|
||||
return buffer;
|
||||
_offset = _initialOffset + position;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
ValidateReceiveBuffer(1);
|
||||
return _buffer[Offset++];
|
||||
}
|
||||
|
||||
return _buffer[_offset++];
|
||||
}
|
||||
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
ValidateReceiveBuffer(1);
|
||||
var buffer = _buffer[Offset++];
|
||||
|
||||
var buffer = _buffer[_offset++];
|
||||
|
||||
if (buffer == 0)
|
||||
{
|
||||
@@ -71,15 +61,19 @@ namespace MQTTnet.Formatter
|
||||
|
||||
public byte[] ReadRemainingData()
|
||||
{
|
||||
return new ArraySegment<byte>(_buffer, (int)Offset, (int)(_length - Offset)).ToArray();
|
||||
var bufferLength = _length - _offset;
|
||||
var buffer = new byte[bufferLength];
|
||||
Array.Copy(_buffer, _offset, buffer, 0, bufferLength);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public ushort ReadTwoByteInteger()
|
||||
{
|
||||
ValidateReceiveBuffer(2);
|
||||
|
||||
var msb = _buffer[Offset++];
|
||||
var lsb = _buffer[Offset++];
|
||||
var msb = _buffer[_offset++];
|
||||
var lsb = _buffer[_offset++];
|
||||
|
||||
return (ushort)(msb << 8 | lsb);
|
||||
}
|
||||
@@ -88,31 +82,14 @@ namespace MQTTnet.Formatter
|
||||
{
|
||||
ValidateReceiveBuffer(4);
|
||||
|
||||
var byte0 = _buffer[Offset++];
|
||||
var byte1 = _buffer[Offset++];
|
||||
var byte2 = _buffer[Offset++];
|
||||
var byte3 = _buffer[Offset++];
|
||||
var byte0 = _buffer[_offset++];
|
||||
var byte1 = _buffer[_offset++];
|
||||
var byte2 = _buffer[_offset++];
|
||||
var byte3 = _buffer[_offset++];
|
||||
|
||||
return (uint)(byte0 << 24 | byte1 << 16 | byte2 << 8 | byte3);
|
||||
}
|
||||
|
||||
public byte[] ReadWithLengthPrefix()
|
||||
{
|
||||
return ReadSegmentWithLengthPrefix().ToArray();
|
||||
}
|
||||
|
||||
private ArraySegment<byte> ReadSegmentWithLengthPrefix()
|
||||
{
|
||||
var length = ReadTwoByteInteger();
|
||||
|
||||
ValidateReceiveBuffer(length);
|
||||
|
||||
var result = new ArraySegment<byte>(_buffer, (int)Offset, length);
|
||||
Offset += length;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint ReadVariableLengthInteger()
|
||||
{
|
||||
var multiplier = 1;
|
||||
@@ -134,13 +111,30 @@ namespace MQTTnet.Formatter
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public byte[] ReadWithLengthPrefix()
|
||||
{
|
||||
return ReadSegmentWithLengthPrefix().ToArray();
|
||||
}
|
||||
|
||||
private ArraySegment<byte> ReadSegmentWithLengthPrefix()
|
||||
{
|
||||
var length = ReadTwoByteInteger();
|
||||
|
||||
ValidateReceiveBuffer(length);
|
||||
|
||||
var result = new ArraySegment<byte>(_buffer, _offset, length);
|
||||
_offset += length;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void ValidateReceiveBuffer(uint length)
|
||||
private void ValidateReceiveBuffer(int length)
|
||||
{
|
||||
if (_length < Offset + length)
|
||||
if (_length < _offset + length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(_buffer), $"Expected at least {Offset + length} bytes but there are only {_length} bytes");
|
||||
throw new ArgumentOutOfRangeException(nameof(_buffer), $"Expected at least {_offset + length} bytes but there are only {_length} bytes");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ namespace MQTTnet.Formatter.V5
|
||||
public class MqttV500PropertiesReader
|
||||
{
|
||||
private readonly IMqttPacketBodyReader _body;
|
||||
private readonly uint _length;
|
||||
private readonly ulong _targetOffset;
|
||||
private readonly int _length;
|
||||
private readonly int _targetOffset;
|
||||
|
||||
public MqttV500PropertiesReader(IMqttPacketBodyReader body)
|
||||
{
|
||||
@@ -18,7 +18,7 @@ namespace MQTTnet.Formatter.V5
|
||||
|
||||
if (!body.EndOfStream)
|
||||
{
|
||||
_length = body.ReadVariableLengthInteger();
|
||||
_length = (int)body.ReadVariableLengthInteger();
|
||||
}
|
||||
|
||||
_targetOffset = body.Offset + _length;
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace MQTTnet.Implementations
|
||||
|
||||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
|
||||
public bool TreatSocketOpeningErrorAsWarning { get; set; }
|
||||
|
||||
public Task StartAsync(IMqttServerOptions options)
|
||||
{
|
||||
if (_cancellationTokenSource != null) throw new InvalidOperationException("Server is already started.");
|
||||
@@ -36,7 +38,7 @@ namespace MQTTnet.Implementations
|
||||
|
||||
if (options.DefaultEndpointOptions.IsEnabled)
|
||||
{
|
||||
RegisterListeners(options.DefaultEndpointOptions, null);
|
||||
RegisterListeners(options.DefaultEndpointOptions, null, _cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
if (options.TlsEndpointOptions.IsEnabled)
|
||||
@@ -52,7 +54,7 @@ namespace MQTTnet.Implementations
|
||||
throw new InvalidOperationException("The certificate for TLS encryption must contain the private key.");
|
||||
}
|
||||
|
||||
RegisterListeners(options.TlsEndpointOptions, tlsCertificate);
|
||||
RegisterListeners(options.TlsEndpointOptions, tlsCertificate, _cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
@@ -78,7 +80,7 @@ namespace MQTTnet.Implementations
|
||||
_listeners.Clear();
|
||||
}
|
||||
|
||||
private void RegisterListeners(MqttServerTcpEndpointBaseOptions options, X509Certificate2 tlsCertificate)
|
||||
private void RegisterListeners(MqttServerTcpEndpointBaseOptions options, X509Certificate2 tlsCertificate, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!options.BoundInterNetworkAddress.Equals(IPAddress.None))
|
||||
{
|
||||
@@ -86,14 +88,15 @@ namespace MQTTnet.Implementations
|
||||
AddressFamily.InterNetwork,
|
||||
options,
|
||||
tlsCertificate,
|
||||
_cancellationTokenSource.Token,
|
||||
_logger)
|
||||
{
|
||||
ClientHandler = OnClientAcceptedAsync
|
||||
};
|
||||
|
||||
listenerV4.Start();
|
||||
_listeners.Add(listenerV4);
|
||||
if (listenerV4.Start(TreatSocketOpeningErrorAsWarning, cancellationToken))
|
||||
{
|
||||
_listeners.Add(listenerV4);
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.BoundInterNetworkV6Address.Equals(IPAddress.None))
|
||||
@@ -102,14 +105,15 @@ namespace MQTTnet.Implementations
|
||||
AddressFamily.InterNetworkV6,
|
||||
options,
|
||||
tlsCertificate,
|
||||
_cancellationTokenSource.Token,
|
||||
_logger)
|
||||
{
|
||||
ClientHandler = OnClientAcceptedAsync
|
||||
};
|
||||
|
||||
listenerV6.Start();
|
||||
_listeners.Add(listenerV6);
|
||||
if (listenerV6.Start(TreatSocketOpeningErrorAsWarning, cancellationToken))
|
||||
{
|
||||
_listeners.Add(listenerV6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
|
||||
using MQTTnet.Adapter;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.Server;
|
||||
|
||||
namespace MQTTnet.Implementations
|
||||
@@ -17,24 +18,23 @@ namespace MQTTnet.Implementations
|
||||
public class MqttTcpServerListener : IDisposable
|
||||
{
|
||||
private readonly IMqttNetChildLogger _logger;
|
||||
private readonly CancellationToken _cancellationToken;
|
||||
private readonly AddressFamily _addressFamily;
|
||||
private readonly MqttServerTcpEndpointBaseOptions _options;
|
||||
private readonly MqttServerTlsTcpEndpointOptions _tlsOptions;
|
||||
private readonly X509Certificate2 _tlsCertificate;
|
||||
|
||||
private Socket _socket;
|
||||
private IPEndPoint _localEndPoint;
|
||||
|
||||
public MqttTcpServerListener(
|
||||
AddressFamily addressFamily,
|
||||
MqttServerTcpEndpointBaseOptions options,
|
||||
X509Certificate2 tlsCertificate,
|
||||
CancellationToken cancellationToken,
|
||||
IMqttNetChildLogger logger)
|
||||
{
|
||||
_addressFamily = addressFamily;
|
||||
_options = options;
|
||||
_tlsCertificate = tlsCertificate;
|
||||
_cancellationToken = cancellationToken;
|
||||
_logger = logger.CreateChildLogger(nameof(MqttTcpServerListener));
|
||||
|
||||
if (_options is MqttServerTlsTcpEndpointOptions tlsOptions)
|
||||
@@ -45,21 +45,38 @@ namespace MQTTnet.Implementations
|
||||
|
||||
public Func<IMqttChannelAdapter, Task> ClientHandler { get; set; }
|
||||
|
||||
public void Start()
|
||||
public bool Start(bool treatErrorsAsWarning, CancellationToken cancellationToken)
|
||||
{
|
||||
var boundIp = _options.BoundInterNetworkAddress;
|
||||
if (_addressFamily == AddressFamily.InterNetworkV6)
|
||||
try
|
||||
{
|
||||
boundIp = _options.BoundInterNetworkV6Address;
|
||||
var boundIp = _options.BoundInterNetworkAddress;
|
||||
if (_addressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
boundIp = _options.BoundInterNetworkV6Address;
|
||||
}
|
||||
|
||||
_localEndPoint = new IPEndPoint(boundIp, _options.Port);
|
||||
|
||||
_logger.Info($"Starting TCP listener for {_localEndPoint} TLS={_tlsCertificate != null}.");
|
||||
|
||||
_socket = new Socket(_addressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
_socket.Bind(_localEndPoint);
|
||||
_socket.Listen(_options.ConnectionBacklog);
|
||||
|
||||
Task.Run(() => AcceptClientConnectionsAsync(cancellationToken), cancellationToken).Forget(_logger);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
if (!treatErrorsAsWarning)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
_socket = new Socket(_addressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
_socket.Bind(new IPEndPoint(boundIp, _options.Port));
|
||||
|
||||
_logger.Info($"Starting TCP listener for {_socket.LocalEndPoint} TLS={_tlsCertificate != null}.");
|
||||
|
||||
_socket.Listen(_options.ConnectionBacklog);
|
||||
Task.Run(() => AcceptClientConnectionsAsync(_cancellationToken), _cancellationToken);
|
||||
_logger.Warning(exception,"Error while creating listener socket for local end point '{0}'.", _localEndPoint);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -82,13 +99,29 @@ namespace MQTTnet.Implementations
|
||||
#else
|
||||
var clientSocket = await _socket.AcceptAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
#pragma warning disable 4014
|
||||
Task.Run(() => TryHandleClientConnectionAsync(clientSocket), cancellationToken);
|
||||
#pragma warning restore 4014
|
||||
|
||||
if (clientSocket == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Task.Run(() => TryHandleClientConnectionAsync(clientSocket), cancellationToken).Forget(_logger);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.Error(exception, $"Error while accepting connection at TCP listener {_socket.LocalEndPoint} TLS={_tlsCertificate != null}.");
|
||||
if (exception is SocketException socketException)
|
||||
{
|
||||
if (socketException.SocketErrorCode == SocketError.ConnectionAborted ||
|
||||
socketException.SocketErrorCode == SocketError.OperationAborted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Error(exception, $"Error while accepting connection at TCP listener {_localEndPoint} TLS={_tlsCertificate != null}.");
|
||||
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -105,7 +138,7 @@ namespace MQTTnet.Implementations
|
||||
|
||||
_logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.",
|
||||
remoteEndPoint,
|
||||
_socket.LocalEndPoint,
|
||||
_localEndPoint,
|
||||
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
|
||||
|
||||
clientSocket.NoDelay = _options.NoDelay;
|
||||
@@ -163,7 +196,7 @@ namespace MQTTnet.Implementations
|
||||
|
||||
_logger.Verbose("Client '{0}' disconnected at TCP listener '{1}, {2}'.",
|
||||
remoteEndPoint,
|
||||
_socket.LocalEndPoint,
|
||||
_localEndPoint,
|
||||
_addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6");
|
||||
}
|
||||
catch (Exception disposeException)
|
||||
|
||||
@@ -7,6 +7,7 @@ using MQTTnet.Client;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Exceptions;
|
||||
using MQTTnet.Formatter;
|
||||
using MQTTnet.Internal;
|
||||
using MQTTnet.PacketDispatcher;
|
||||
using MQTTnet.Packets;
|
||||
using MQTTnet.Protocol;
|
||||
@@ -134,9 +135,7 @@ namespace MQTTnet.Server
|
||||
|
||||
Session.WillMessage = _connectPacket.WillMessage;
|
||||
|
||||
#pragma warning disable 4014
|
||||
Task.Run(() => SendPendingPacketsAsync(_cancellationToken.Token), _cancellationToken.Token);
|
||||
#pragma warning restore 4014
|
||||
Task.Run(() => SendPendingPacketsAsync(_cancellationToken.Token), _cancellationToken.Token).Forget(_logger);
|
||||
|
||||
// TODO: Change to single thread in SessionManager. Or use SessionManager and stats from KeepAliveMonitor.
|
||||
_keepAliveMonitor.Start(_connectPacket.KeepAlivePeriod, _cancellationToken.Token);
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using MQTTnet.Diagnostics;
|
||||
using MQTTnet.Internal;
|
||||
|
||||
namespace MQTTnet.Server
|
||||
{
|
||||
@@ -32,7 +33,7 @@ namespace MQTTnet.Server
|
||||
return;
|
||||
}
|
||||
|
||||
Task.Run(() => RunAsync(keepAlivePeriod, cancellationToken), cancellationToken).ConfigureAwait(false);
|
||||
Task.Run(() => RunAsync(keepAlivePeriod, cancellationToken), cancellationToken).Forget(_logger);
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace MQTTnet.Server
|
||||
|
||||
public void Start()
|
||||
{
|
||||
Task.Run(() => TryProcessQueuedApplicationMessagesAsync(_cancellationToken), _cancellationToken);
|
||||
Task.Run(() => TryProcessQueuedApplicationMessagesAsync(_cancellationToken), _cancellationToken).Forget(_logger);
|
||||
}
|
||||
|
||||
public async Task StopAsync()
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace MQTTnet.Benchmarks
|
||||
|
||||
var receivedPacket = new ReceivedMqttPacket(
|
||||
header.Flags,
|
||||
new MqttPacketBodyReader(_serializedPacket.Array, (ulong)(_serializedPacket.Count - header.RemainingLength), (ulong)_serializedPacket.Array.Length), 0);
|
||||
new MqttPacketBodyReader(_serializedPacket.Array, _serializedPacket.Count - header.RemainingLength, _serializedPacket.Array.Length), 0);
|
||||
|
||||
_serializer.Decode(receivedPacket);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using MQTTnet.Formatter;
|
||||
|
||||
namespace MQTTnet.Tests
|
||||
{
|
||||
[TestClass]
|
||||
public class Protocol_Tests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Encode_Four_Byte_Integer()
|
||||
{
|
||||
for (uint i = 0; i < 268435455; i++)
|
||||
{
|
||||
var buffer = MqttPacketWriter.EncodeVariableLengthInteger(i);
|
||||
var reader = new MqttPacketBodyReader(buffer.Array, buffer.Offset, buffer.Count);
|
||||
|
||||
var checkValue = reader.ReadVariableLengthInteger();
|
||||
|
||||
Assert.AreEqual(i, checkValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,27 @@ namespace MQTTnet.Tests
|
||||
[TestClass]
|
||||
public class Server_Tests
|
||||
{
|
||||
[TestMethod]
|
||||
public async Task Use_Empty_Client_ID()
|
||||
{
|
||||
using (var testEnvironment = new TestEnvironment())
|
||||
{
|
||||
await testEnvironment.StartServerAsync();
|
||||
|
||||
var client = testEnvironment.CreateClient();
|
||||
|
||||
var clientOptions = new MqttClientOptionsBuilder()
|
||||
.WithTcpServer("localhost", testEnvironment.ServerPort)
|
||||
.WithClientId(string.Empty)
|
||||
.Build();
|
||||
|
||||
var connectResult = await client.ConnectAsync(clientOptions);
|
||||
|
||||
Assert.IsFalse(connectResult.IsSessionPresent);
|
||||
Assert.IsTrue(client.IsConnected);
|
||||
}
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public async Task Publish_At_Most_Once_0x00()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user