Improve performance and drop support for old frameworks (#2068)

* Remove WebSocket4Net extension library

* Remove UWP support

* Drop support for all old frameworks

* Update CI

* Update CI

* Update CI

* Update CI

* Remove obsolete code

* Set default protocol version to 5.0.0

* Remove obsolete tests

* Remove old dependencies

* Reset release notes

* Move server to dedicated project

* Fix unit tests

* Update and cleanup nuget packages

* Fix unit tests
Refactor code

* No longer throw exception when receiving non success CONNACK

* Enable nuget signing

* Enable nuget signing

* Enable nuget signing

* Enable nuget signing

* Enable nuget signing

* Enable nuget signing

* Enable nuget signing

* Enable nuget signing

* Enable code signing

* Enable code signing

* Enable code signing

* Fix client endpoint handling

* Improve CI

* Fix CI

* Fix CI

* Fix CI

* Fix CI

* Import changes from version 4

* Cleanup target frameworks and remove obsolete code

* Drop support for dotnet7.0

* Remove managed client

* Version5 auditmode (#2016)

Added NuGet audit mode and some other settings to get informed about security issues.

* Address warnings from analyzers

* Support for ReadOnlySequence as payload (#2046)

* use ReadOnlySequence as payload

* fix build

* fix build

* skip sign in forks

* remove unnecessary owner

* tests and extensions

* remove test

* simplify WritePacketBuffer, remove unused helper

* Adjust namespaces

* Fix build errors

* Import latest fixes from main branch

* Adjust namespaces

---------

Co-authored-by: SeppPenner <HansM2013@gmx.de>
Co-authored-by: Martin Regen <mregen@microsoft.com>
This commit is contained in:
Christian
2024-08-24 11:47:21 +02:00
committed by GitHub
co-authored by SeppPenner Martin Regen
parent e18a91a4b5
commit 980a5d0a6d
459 changed files with 12197 additions and 16662 deletions
@@ -0,0 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace MQTTnet.Server
{
public interface IMqttServerCertificateCredentials
{
string Password { get; }
}
}
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace MQTTnet.Server
{
public enum MqttPendingMessagesOverflowStrategy
{
DropOldestQueuedMessage,
DropNewMessage
}
}
@@ -0,0 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace MQTTnet.Server
{
public class MqttServerCertificateCredentials : IMqttServerCertificateCredentials
{
public string Password { get; set; }
}
}
@@ -0,0 +1,21 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace MQTTnet.Server
{
public sealed class MqttServerKeepAliveOptions
{
/// <summary>
/// When this mode is enabled the MQTT server will not close a connection when the
/// client is currently sending a (large) payload. This may lead to "dead" connections
/// When this mode is disabled the MQTT server will disconnect a client when the keep
/// alive timeout is reached even if the client is currently sending a (large) payload.
/// </summary>
public bool DisconnectClientWhenReadingPayload { get; set; }
public TimeSpan MonitorInterval { get; set; } = TimeSpan.FromMilliseconds(500);
}
}
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
namespace MQTTnet.Server
{
public sealed class MqttServerOptions
{
public TimeSpan DefaultCommunicationTimeout { get; set; } = TimeSpan.FromSeconds(100);
public MqttServerTcpEndpointOptions DefaultEndpointOptions { get; } = new MqttServerTcpEndpointOptions();
public bool EnablePersistentSessions { get; set; }
public MqttServerKeepAliveOptions KeepAliveOptions { get; } = new MqttServerKeepAliveOptions();
public int MaxPendingMessagesPerClient { get; set; } = 250;
public MqttPendingMessagesOverflowStrategy PendingMessagesOverflowStrategy { get; set; } = MqttPendingMessagesOverflowStrategy.DropOldestQueuedMessage;
public MqttServerTlsTcpEndpointOptions TlsEndpointOptions { get; } = new MqttServerTlsTcpEndpointOptions();
/// <summary>
/// Gets or sets the default and initial size of the packet write buffer.
/// It is recommended to set this to a value close to the usual expected packet size * 1.5.
/// Do not change this value when no memory issues are experienced.
/// </summary>
public int WriterBufferSize { get; set; } = 4096;
/// <summary>
/// Gets or sets the maximum size of the buffer writer. The writer will reduce its internal buffer
/// to this value after serializing a packet.
/// Do not change this value when no memory issues are experienced.
/// </summary>
public int WriterBufferSizeMax { get; set; } = 65535;
}
}
@@ -0,0 +1,219 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using MQTTnet.Certificates;
using System.Security.Cryptography.X509Certificates;
// ReSharper disable UnusedMember.Global
namespace MQTTnet.Server
{
public class MqttServerOptionsBuilder
{
readonly MqttServerOptions _options = new MqttServerOptions();
public MqttServerOptions Build()
{
return _options;
}
public MqttServerOptionsBuilder WithClientCertificate(RemoteCertificateValidationCallback validationCallback = null, bool checkCertificateRevocation = false)
{
_options.TlsEndpointOptions.ClientCertificateRequired = true;
_options.TlsEndpointOptions.CheckCertificateRevocation = checkCertificateRevocation;
_options.TlsEndpointOptions.RemoteCertificateValidationCallback = validationCallback;
return this;
}
public MqttServerOptionsBuilder WithConnectionBacklog(int value)
{
_options.DefaultEndpointOptions.ConnectionBacklog = value;
_options.TlsEndpointOptions.ConnectionBacklog = value;
return this;
}
public MqttServerOptionsBuilder WithDefaultCommunicationTimeout(TimeSpan value)
{
_options.DefaultCommunicationTimeout = value;
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpoint()
{
_options.DefaultEndpointOptions.IsEnabled = true;
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpointBoundIPAddress(IPAddress value)
{
_options.DefaultEndpointOptions.BoundInterNetworkAddress = value ?? IPAddress.Any;
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpointBoundIPV6Address(IPAddress value)
{
_options.DefaultEndpointOptions.BoundInterNetworkV6Address = value ?? IPAddress.Any;
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpointPort(int value)
{
_options.DefaultEndpointOptions.Port = value;
return this;
}
public MqttServerOptionsBuilder WithDefaultEndpointReuseAddress()
{
_options.DefaultEndpointOptions.ReuseAddress = true;
return this;
}
public MqttServerOptionsBuilder WithEncryptedEndpoint()
{
_options.TlsEndpointOptions.IsEnabled = true;
return this;
}
public MqttServerOptionsBuilder WithEncryptedEndpointBoundIPAddress(IPAddress value)
{
_options.TlsEndpointOptions.BoundInterNetworkAddress = value;
return this;
}
public MqttServerOptionsBuilder WithEncryptedEndpointBoundIPV6Address(IPAddress value)
{
_options.TlsEndpointOptions.BoundInterNetworkV6Address = value;
return this;
}
public MqttServerOptionsBuilder WithEncryptedEndpointPort(int value)
{
_options.TlsEndpointOptions.Port = value;
return this;
}
public MqttServerOptionsBuilder WithEncryptionSslProtocol(SslProtocols value)
{
_options.TlsEndpointOptions.SslProtocol = value;
return this;
}
public MqttServerOptionsBuilder WithKeepAlive()
{
_options.DefaultEndpointOptions.KeepAlive = true;
_options.TlsEndpointOptions.KeepAlive = true;
return this;
}
public MqttServerOptionsBuilder WithMaxPendingMessagesPerClient(int value)
{
_options.MaxPendingMessagesPerClient = value;
return this;
}
public MqttServerOptionsBuilder WithoutDefaultEndpoint()
{
_options.DefaultEndpointOptions.IsEnabled = false;
return this;
}
public MqttServerOptionsBuilder WithoutEncryptedEndpoint()
{
_options.TlsEndpointOptions.IsEnabled = false;
return this;
}
/// <summary>
/// Usually the MQTT packets can be send partially to improve memory allocations.
/// This is done by using multiple TCP packets or WebSocket frames etc.
/// Unfortunately not all clients do support this and will close the connection when receiving partial packets.
/// </summary>
public MqttServerOptionsBuilder WithoutPacketFragmentation()
{
_options.DefaultEndpointOptions.AllowPacketFragmentation = false;
_options.TlsEndpointOptions.AllowPacketFragmentation = false;
return this;
}
public MqttServerOptionsBuilder WithPersistentSessions(bool value = true)
{
_options.EnablePersistentSessions = value;
return this;
}
public MqttServerOptionsBuilder WithRemoteCertificateValidationCallback(RemoteCertificateValidationCallback value)
{
_options.TlsEndpointOptions.RemoteCertificateValidationCallback = value;
return this;
}
public MqttServerOptionsBuilder WithTcpKeepAliveInterval(int value)
{
_options.DefaultEndpointOptions.TcpKeepAliveInterval = value;
_options.TlsEndpointOptions.TcpKeepAliveInterval = value;
return this;
}
public MqttServerOptionsBuilder WithTcpKeepAliveRetryCount(int value)
{
_options.DefaultEndpointOptions.TcpKeepAliveRetryCount = value;
_options.TlsEndpointOptions.TcpKeepAliveRetryCount = value;
return this;
}
public MqttServerOptionsBuilder WithTcpKeepAliveTime(int value)
{
_options.DefaultEndpointOptions.TcpKeepAliveTime = value;
_options.TlsEndpointOptions.TcpKeepAliveTime = value;
return this;
}
public MqttServerOptionsBuilder WithTlsEndpointReuseAddress()
{
_options.TlsEndpointOptions.ReuseAddress = true;
return this;
}
public MqttServerOptionsBuilder WithEncryptionCertificate(byte[] value, IMqttServerCertificateCredentials credentials = null)
{
if (value == null)
{
throw new ArgumentNullException(nameof(value));
}
_options.TlsEndpointOptions.CertificateProvider = new BlobCertificateProvider(value)
{
Password = credentials?.Password
};
return this;
}
public MqttServerOptionsBuilder WithEncryptionCertificate(X509Certificate2 certificate)
{
if (certificate == null)
{
throw new ArgumentNullException(nameof(certificate));
}
_options.TlsEndpointOptions.CertificateProvider = new X509CertificateProvider(certificate);
return this;
}
public MqttServerOptionsBuilder WithEncryptionCertificate(ICertificateProvider certificateProvider)
{
if (certificateProvider == null)
{
throw new ArgumentNullException(nameof(certificateProvider));
}
_options.TlsEndpointOptions.CertificateProvider = certificateProvider;
return this;
}
}
}
@@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Net;
using System.Net.Sockets;
namespace MQTTnet.Server
{
public abstract class MqttServerTcpEndpointBaseOptions
{
public bool IsEnabled { get; set; }
public int Port { get; set; }
public int ConnectionBacklog { get; set; } = 100;
public bool NoDelay { get; set; } = true;
/// <summary>
/// Gets or sets whether the sockets keep alive feature should be used.
/// The value _null_ indicates that the OS and framework defaults should be used.
/// </summary>
public bool? KeepAlive { get; set; }
/// <summary>
/// Usually the MQTT packets can be send partially. This is done by using multiple TCP packets
/// or WebSocket frames etc. Unfortunately not all clients do support this feature and
/// will close the connection when receiving such packets. If such clients are connecting to this
/// server the flag must be set to _false_.
/// </summary>
public bool AllowPacketFragmentation { get; set; } = true;
/// <summary>
/// Gets or sets the TCP keep alive interval.
/// The value _null_ indicates that the OS and framework defaults should be used.
/// </summary>
public int? TcpKeepAliveInterval { get; set; }
/// <summary>
/// Gets or sets the TCP keep alive retry count.
/// The value _null_ indicates that the OS and framework defaults should be used.
/// </summary>
public int? TcpKeepAliveRetryCount { get; set; }
/// <summary>
/// Gets or sets the TCP keep alive time.
/// The value _null_ indicates that the OS and framework defaults should be used.
/// </summary>
public int? TcpKeepAliveTime { get; set; }
public LingerOption LingerState { get; set; } = new LingerOption(true, 0);
public IPAddress BoundInterNetworkAddress { get; set; } = IPAddress.Any;
public IPAddress BoundInterNetworkV6Address { get; set; } = IPAddress.IPv6Any;
/// <summary>
/// This requires admin permissions on Linux.
/// </summary>
public bool ReuseAddress { get; set; }
}
}
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace MQTTnet.Server
{
public class MqttServerTcpEndpointOptions : MqttServerTcpEndpointBaseOptions
{
public MqttServerTcpEndpointOptions()
{
Port = 1883;
}
}
}
@@ -0,0 +1,29 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Security.Authentication;
using MQTTnet.Certificates;
namespace MQTTnet.Server
{
public sealed class MqttServerTlsTcpEndpointOptions : MqttServerTcpEndpointBaseOptions
{
public MqttServerTlsTcpEndpointOptions()
{
Port = 8883;
}
public System.Net.Security.RemoteCertificateValidationCallback RemoteCertificateValidationCallback { get; set; }
public ICertificateProvider CertificateProvider { get; set; }
public bool ClientCertificateRequired { get; set; }
public bool CheckCertificateRevocation { get; set; }
public SslProtocols SslProtocol { get; set; } = SslProtocols.Tls12;
public System.Net.Security.CipherSuitesPolicy CipherSuitesPolicy { get; set; }
}
}