mirror of
https://github.com/dotnet/MQTTnet.git
synced 2026-10-18 02:13:00 +08:00
1544 add underlying socketoption of tcp keepalive into the server option (#1606)
* Expose TCP keep alive options to options builder * Update ReleaseNotes.md
This commit is contained in:
@@ -72,8 +72,8 @@ namespace MQTTnet.Implementations
|
||||
get => _socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval) as int? ?? 0;
|
||||
set => _socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveInterval, value);
|
||||
#else
|
||||
get { throw new NotSupportedException("TcpKeepAliveInterval requires at least net5.0."); }
|
||||
set { throw new NotSupportedException("TcpKeepAliveInterval requires at least net5.0."); }
|
||||
get { throw new NotSupportedException("TcpKeepAliveInterval requires at least netcoreapp3.0."); }
|
||||
set { throw new NotSupportedException("TcpKeepAliveInterval requires at least netcoreapp3.0."); }
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -83,8 +83,8 @@ namespace MQTTnet.Implementations
|
||||
get => _socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount) as int? ?? 0;
|
||||
set => _socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveRetryCount, value);
|
||||
#else
|
||||
get { throw new NotSupportedException("TcpKeepAliveRetryCount requires at least net5.0."); }
|
||||
set { throw new NotSupportedException("TcpKeepAliveRetryCount requires at least net5.0."); }
|
||||
get { throw new NotSupportedException("TcpKeepAliveRetryCount requires at least netcoreapp3.0."); }
|
||||
set { throw new NotSupportedException("TcpKeepAliveRetryCount requires at least netcoreapp3.0."); }
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ namespace MQTTnet.Implementations
|
||||
get => _socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime) as int? ?? 0;
|
||||
set => _socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, value);
|
||||
#else
|
||||
get { throw new NotSupportedException("TcpKeepAliveTime requires at least net5.0."); }
|
||||
set { throw new NotSupportedException("TcpKeepAliveTime requires at least net5.0."); }
|
||||
get { throw new NotSupportedException("TcpKeepAliveTime requires at least netcoreapp3.0."); }
|
||||
set { throw new NotSupportedException("TcpKeepAliveTime requires at least netcoreapp3.0."); }
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ namespace MQTTnet.Implementations
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// This will happen when _socket.EndAccept gets called by Task library but the socket is already disposed.
|
||||
// This will happen when _socket.EndAccept_ gets called by Task library but the socket is already disposed.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -181,16 +181,18 @@ namespace MQTTnet.Implementations
|
||||
|
||||
try
|
||||
{
|
||||
#if NET5_0_OR_GREATER
|
||||
#if NETCOREAPP3_0_OR_GREATER
|
||||
if (_networkStream != null)
|
||||
{
|
||||
await _networkStream.DisposeAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
await _socket.ConnectAsync(host, port, cancellationToken).ConfigureAwait(false);
|
||||
#else
|
||||
_networkStream?.Dispose();
|
||||
#endif
|
||||
|
||||
#if NET5_0_OR_GREATER
|
||||
await _socket.ConnectAsync(host, port, cancellationToken).ConfigureAwait(false);
|
||||
#else
|
||||
// Workaround for: https://github.com/dotnet/corefx/issues/24430
|
||||
using (cancellationToken.Register(_socketDisposeAction))
|
||||
{
|
||||
@@ -219,7 +221,7 @@ namespace MQTTnet.Implementations
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// This will happen when _socket.EndConnect gets called by Task library but the socket is already disposed.
|
||||
// This will happen when _socket.EndConnect_ gets called by Task library but the socket is already disposed.
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
@@ -246,38 +248,44 @@ namespace MQTTnet.Implementations
|
||||
_socket.Listen(connectionBacklog);
|
||||
}
|
||||
|
||||
#if NET452 || NET461
|
||||
public async Task<int> ReceiveAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if NET452 || NET461
|
||||
return await Task.Factory.FromAsync(SocketWrapper.BeginReceive, _socket.EndReceive, new SocketWrapper(_socket, buffer, socketFlags)).ConfigureAwait(false);
|
||||
#else
|
||||
return await _socket.ReceiveAsync(buffer, socketFlags).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// This will happen when _socket.EndReceive gets called by Task library but the socket is already disposed.
|
||||
// This will happen when _socket.EndReceive_ gets called by Task library but the socket is already disposed.
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public Task<int> ReceiveAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
return _socket.ReceiveAsync(buffer, socketFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NET452 || NET461
|
||||
public async Task SendAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if NET452 || NET461
|
||||
await Task.Factory.FromAsync(SocketWrapper.BeginSend, _socket.EndSend, new SocketWrapper(_socket, buffer, socketFlags)).ConfigureAwait(false);
|
||||
#else
|
||||
await _socket.SendAsync(buffer, socketFlags).ConfigureAwait(false);
|
||||
#endif
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// This will happen when _socket.EndConnect gets called by Task library but the socket is already disposed.
|
||||
// This will happen when _socket.EndSend_ gets called by Task library but the socket is already disposed.
|
||||
}
|
||||
}
|
||||
#else
|
||||
public Task SendAsync(ArraySegment<byte> buffer, SocketFlags socketFlags)
|
||||
{
|
||||
return _socket.SendAsync(buffer, socketFlags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if NET452 || NET461
|
||||
sealed class SocketWrapper
|
||||
|
||||
@@ -86,6 +86,26 @@ namespace MQTTnet.Implementations
|
||||
_socket.LingerState = _options.LingerState;
|
||||
}
|
||||
|
||||
if (_options.KeepAlive.HasValue)
|
||||
{
|
||||
_socket.KeepAlive = _options.KeepAlive.Value;
|
||||
}
|
||||
|
||||
if (_options.TcpKeepAliveInterval.HasValue)
|
||||
{
|
||||
_socket.TcpKeepAliveInterval = _options.TcpKeepAliveInterval.Value;
|
||||
}
|
||||
|
||||
if (_options.TcpKeepAliveRetryCount.HasValue)
|
||||
{
|
||||
_socket.TcpKeepAliveInterval = _options.TcpKeepAliveRetryCount.Value;
|
||||
}
|
||||
|
||||
if (_options.TcpKeepAliveTime.HasValue)
|
||||
{
|
||||
_socket.TcpKeepAliveTime = _options.TcpKeepAliveTime.Value;
|
||||
}
|
||||
|
||||
_socket.Bind(_localEndPoint);
|
||||
|
||||
// Get the local endpoint back from the socket. The port may have changed.
|
||||
|
||||
@@ -7,8 +7,6 @@ using System.Net;
|
||||
using System.Net.Security;
|
||||
using System.Security.Authentication;
|
||||
using MQTTnet.Certificates;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
#if !WINDOWS_UWP
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
#endif
|
||||
@@ -19,7 +17,22 @@ namespace MQTTnet.Server
|
||||
public class MqttServerOptionsBuilder
|
||||
{
|
||||
readonly MqttServerOptions _options = new MqttServerOptions();
|
||||
|
||||
|
||||
public MqttServerOptions Build()
|
||||
{
|
||||
return _options;
|
||||
}
|
||||
|
||||
#if !WINDOWS_UWP
|
||||
public MqttServerOptionsBuilder WithClientCertificate(RemoteCertificateValidationCallback validationCallback = null, bool checkCertificateRevocation = false)
|
||||
{
|
||||
_options.TlsEndpointOptions.ClientCertificateRequired = true;
|
||||
_options.TlsEndpointOptions.CheckCertificateRevocation = checkCertificateRevocation;
|
||||
_options.TlsEndpointOptions.RemoteCertificateValidationCallback = validationCallback;
|
||||
return this;
|
||||
}
|
||||
#endif
|
||||
|
||||
public MqttServerOptionsBuilder WithConnectionBacklog(int value)
|
||||
{
|
||||
_options.DefaultEndpointOptions.ConnectionBacklog = value;
|
||||
@@ -27,12 +40,6 @@ namespace MQTTnet.Server
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithMaxPendingMessagesPerClient(int value)
|
||||
{
|
||||
_options.MaxPendingMessagesPerClient = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithDefaultCommunicationTimeout(TimeSpan value)
|
||||
{
|
||||
_options.DefaultCommunicationTimeout = value;
|
||||
@@ -45,12 +52,6 @@ namespace MQTTnet.Server
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithDefaultEndpointPort(int value)
|
||||
{
|
||||
_options.DefaultEndpointOptions.Port = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithDefaultEndpointBoundIPAddress(IPAddress value)
|
||||
{
|
||||
_options.DefaultEndpointOptions.BoundInterNetworkAddress = value ?? IPAddress.Any;
|
||||
@@ -63,9 +64,15 @@ namespace MQTTnet.Server
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithoutDefaultEndpoint()
|
||||
public MqttServerOptionsBuilder WithDefaultEndpointPort(int value)
|
||||
{
|
||||
_options.DefaultEndpointOptions.IsEnabled = false;
|
||||
_options.DefaultEndpointOptions.Port = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithDefaultEndpointReuseAddress()
|
||||
{
|
||||
_options.DefaultEndpointOptions.ReuseAddress = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -75,12 +82,6 @@ namespace MQTTnet.Server
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithEncryptedEndpointPort(int value)
|
||||
{
|
||||
_options.TlsEndpointOptions.Port = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithEncryptedEndpointBoundIPAddress(IPAddress value)
|
||||
{
|
||||
_options.TlsEndpointOptions.BoundInterNetworkAddress = value;
|
||||
@@ -93,10 +94,91 @@ namespace MQTTnet.Server
|
||||
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;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithPersistentSessions(bool value = true)
|
||||
{
|
||||
_options.EnablePersistentSessions = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
#if !WINDOWS_UWP
|
||||
public MqttServerOptionsBuilder WithRemoteCertificateValidationCallback(RemoteCertificateValidationCallback value)
|
||||
{
|
||||
_options.TlsEndpointOptions.RemoteCertificateValidationCallback = value;
|
||||
return this;
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#if !WINDOWS_UWP
|
||||
public MqttServerOptionsBuilder WithEncryptionCertificate(byte[] value, IMqttServerCertificateCredentials credentials = null)
|
||||
{
|
||||
if (value == null) throw new ArgumentNullException(nameof(value));
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(value));
|
||||
}
|
||||
|
||||
_options.TlsEndpointOptions.CertificateProvider = new BlobCertificateProvider(value)
|
||||
{
|
||||
@@ -108,103 +190,14 @@ namespace MQTTnet.Server
|
||||
|
||||
public MqttServerOptionsBuilder WithEncryptionCertificate(X509Certificate2 certificate)
|
||||
{
|
||||
if (certificate == null) throw new ArgumentNullException(nameof(certificate));
|
||||
if (certificate == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(certificate));
|
||||
}
|
||||
|
||||
_options.TlsEndpointOptions.CertificateProvider = new X509CertificateProvider(certificate);
|
||||
return this;
|
||||
}
|
||||
#endif
|
||||
|
||||
public MqttServerOptionsBuilder WithEncryptionSslProtocol(SslProtocols value)
|
||||
{
|
||||
_options.TlsEndpointOptions.SslProtocol = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
#if !WINDOWS_UWP
|
||||
public MqttServerOptionsBuilder WithClientCertificate(RemoteCertificateValidationCallback validationCallback = null, bool checkCertificateRevocation = false)
|
||||
{
|
||||
_options.TlsEndpointOptions.ClientCertificateRequired = true;
|
||||
_options.TlsEndpointOptions.CheckCertificateRevocation = checkCertificateRevocation;
|
||||
_options.TlsEndpointOptions.RemoteCertificateValidationCallback = validationCallback;
|
||||
return this;
|
||||
}
|
||||
#endif
|
||||
|
||||
public MqttServerOptionsBuilder WithoutEncryptedEndpoint()
|
||||
{
|
||||
_options.TlsEndpointOptions.IsEnabled = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
#if !WINDOWS_UWP
|
||||
public MqttServerOptionsBuilder WithRemoteCertificateValidationCallback(RemoteCertificateValidationCallback value)
|
||||
{
|
||||
_options.TlsEndpointOptions.RemoteCertificateValidationCallback = value;
|
||||
return this;
|
||||
}
|
||||
#endif
|
||||
|
||||
// public MqttServerOptionsBuilder WithApplicationMessageInterceptor(IMqttServerApplicationMessageInterceptor value)
|
||||
// {
|
||||
// _options.ApplicationMessageInterceptor = value;
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public MqttServerOptionsBuilder WithApplicationMessageInterceptor(Action<InterceptingMqttClientPublishEventArgs> value)
|
||||
// {
|
||||
// _options.ApplicationMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(value);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public MqttServerOptionsBuilder WithApplicationMessageInterceptor(Func<InterceptingMqttClientPublishEventArgs, Task> value)
|
||||
// {
|
||||
// _options.ApplicationMessageInterceptor = new MqttServerApplicationMessageInterceptorDelegate(value);
|
||||
// return this;
|
||||
// }
|
||||
|
||||
// public MqttServerOptionsBuilder WithMultiThreadedApplicationMessageInterceptor(Action<InterceptingMqttClientPublishEventArgs> value)
|
||||
// {
|
||||
// _options.ApplicationMessageInterceptor = new MqttServerMultiThreadedApplicationMessageInterceptorDelegate(value);
|
||||
// return this;
|
||||
// }
|
||||
//
|
||||
// public MqttServerOptionsBuilder WithMultiThreadedApplicationMessageInterceptor(Func<InterceptingMqttClientPublishEventArgs, Task> value)
|
||||
// {
|
||||
// _options.ApplicationMessageInterceptor = new MqttServerMultiThreadedApplicationMessageInterceptorDelegate(value);
|
||||
// return this;
|
||||
// }
|
||||
|
||||
public MqttServerOptionsBuilder WithDefaultEndpointReuseAddress()
|
||||
{
|
||||
_options.DefaultEndpointOptions.ReuseAddress = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithTlsEndpointReuseAddress()
|
||||
{
|
||||
_options.TlsEndpointOptions.ReuseAddress = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MqttServerOptionsBuilder WithPersistentSessions(bool value = true)
|
||||
{
|
||||
_options.EnablePersistentSessions = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// Gets or sets the client ID which is used when publishing messages from the server directly.
|
||||
// /// </summary>
|
||||
// public MqttServerOptionsBuilder WithClientId(string value)
|
||||
// {
|
||||
// _options.ClientId = value;
|
||||
// return this;
|
||||
// }
|
||||
|
||||
public MqttServerOptions Build()
|
||||
{
|
||||
return _options;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,30 @@ namespace MQTTnet.Server
|
||||
|
||||
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>
|
||||
/// 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);
|
||||
|
||||
#if WINDOWS_UWP
|
||||
|
||||
Reference in New Issue
Block a user