1908 support unix domain sockets (#1919)

* Add support for custom endpoints

Add overlaods etc. to allow for passing other endpoint implementations

* Extend publich broker test to also probe with different protocol versions

* Fix UWP build

* Update ReleaseNotes.md
This commit is contained in:
Christian
2024-02-06 17:37:07 +01:00
committed by GitHub
parent eb25500f50
commit c12096705f
19 changed files with 172 additions and 110 deletions
@@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using MQTTnet.Formatter;
using MQTTnet.Packets;
@@ -22,7 +23,9 @@ namespace MQTTnet.Client
MqttClientTcpOptions _tcpOptions;
MqttClientTlsOptions _tlsOptions;
EndPoint _remoteEndPoint;
int? _port;
[Obsolete] MqttClientOptionsBuilderTlsParameters _tlsParameters;
MqttClientWebSocketOptions _webSocketOptions;
@@ -63,6 +66,31 @@ namespace MQTTnet.Client
if (_tcpOptions != null)
{
_tcpOptions.TlsOptions = tlsOptions;
if (_remoteEndPoint == null)
{
throw new ArgumentException("No endpoint is set.");
}
if (_remoteEndPoint is DnsEndPoint dns)
{
if (dns.Port == 0)
{
if (_port.HasValue)
{
_remoteEndPoint = new DnsEndPoint(dns.Host, _port.Value);
}
else
{
_remoteEndPoint = new DnsEndPoint(dns.Host, tlsOptions?.UseTls == false ? MqttPorts.Default : MqttPorts.Secure);
}
}
}
if (_tcpOptions.RemoteEndpoint == null)
{
_tcpOptions.RemoteEndpoint = _remoteEndPoint;
}
}
else if (_webSocketOptions != null)
{
@@ -307,11 +335,20 @@ namespace MQTTnet.Client
public MqttClientOptionsBuilder WithTcpServer(string server, int? port = null)
{
_tcpOptions = new MqttClientTcpOptions
{
Server = server,
Port = port
};
_tcpOptions = new MqttClientTcpOptions();
// The value 0 will be updated when building the options.
// This a backward compatibility feature.
_remoteEndPoint = new DnsEndPoint(server, port ?? 0);
_port = port;
return this;
}
public MqttClientOptionsBuilder WithEndPoint(EndPoint endPoint)
{
_remoteEndPoint = endPoint ?? throw new ArgumentNullException(nameof(endPoint));
_tcpOptions = new MqttClientTcpOptions();
return this;
}
@@ -11,34 +11,32 @@ namespace MQTTnet.Client
{
public AddressFamily AddressFamily { get; set; } = AddressFamily.Unspecified;
/// <summary>
/// Gets the local endpoint (network card) which is used by the client.
/// Set it to _null_ to let the OS select the network card.
/// </summary>
public EndPoint LocalEndpoint { get; set; }
public int BufferSize { get; set; } = 8192;
/// <summary>
/// Gets or sets whether the underlying socket should run in dual mode.
/// Leaving this _null_ will avoid setting this value at socket level.
/// Setting this a value other than _null_ will throw an exception when only IPv4 is supported on the machine.
/// Gets or sets whether the underlying socket should run in dual mode.
/// Leaving this _null_ will avoid setting this value at socket level.
/// Setting this a value other than _null_ will throw an exception when only IPv4 is supported on the machine.
/// </summary>
public bool? DualMode { get; set; }
public LingerOption LingerState { get; set; } = new LingerOption(true, 0);
/// <summary>
/// Gets the local endpoint (network card) which is used by the client.
/// Set it to _null_ to let the OS select the network card.
/// </summary>
public EndPoint LocalEndpoint { get; set; }
public bool NoDelay { get; set; } = true;
public int? Port { get; set; }
public string Server { get; set; }
public EndPoint RemoteEndpoint { get; set; }
public MqttClientTlsOptions TlsOptions { get; set; } = new MqttClientTlsOptions();
public override string ToString()
{
return Server + ":" + this.GetPort();
return RemoteEndpoint?.ToString() ?? string.Empty;
}
}
}
@@ -1,23 +0,0 @@
// 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.Client
{
public static class MqttClientTcpOptionsExtensions
{
public static int GetPort(this MqttClientTcpOptions options)
{
if (options == null) throw new ArgumentNullException(nameof(options));
if (options.Port.HasValue)
{
return options.Port.Value;
}
return !(options.TlsOptions?.UseTls ?? false) ? 1883 : 8883;
}
}
}
@@ -170,11 +170,16 @@ namespace MQTTnet.Implementations
_socket.Bind(localEndPoint);
}
public async Task ConnectAsync(string host, int port, CancellationToken cancellationToken)
public Task ConnectAsync(string host, int port, CancellationToken cancellationToken)
{
if (host is null)
return ConnectAsync(new DnsEndPoint(host, port), cancellationToken);
}
public async Task ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken)
{
if (endPoint is null)
{
throw new ArgumentNullException(nameof(host));
throw new ArgumentNullException(nameof(endPoint));
}
cancellationToken.ThrowIfCancellationRequested();
@@ -191,15 +196,15 @@ namespace MQTTnet.Implementations
#endif
#if NET5_0_OR_GREATER
await _socket.ConnectAsync(host, port, cancellationToken).ConfigureAwait(false);
await _socket.ConnectAsync(endPoint, cancellationToken).ConfigureAwait(false);
#else
// Workaround for: https://github.com/dotnet/corefx/issues/24430
using (cancellationToken.Register(_socketDisposeAction))
{
#if NET452 || NET461
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, host, port, null).ConfigureAwait(false);
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, endPoint, null).ConfigureAwait(false);
#else
await _socket.ConnectAsync(host, port).ConfigureAwait(false);
await _socket.ConnectAsync(endPoint).ConfigureAwait(false);
#endif
}
#endif
@@ -217,7 +222,7 @@ namespace MQTTnet.Implementations
throw new MqttCommunicationTimedOutException();
}
throw new MqttCommunicationException($"Error while connecting with host '{host}:{port}'.", socketException);
throw new MqttCommunicationException($"Error while connecting host '{endPoint}'.", socketException);
}
catch (ObjectDisposedException)
{
@@ -17,6 +17,7 @@ using MQTTnet.Channel;
using MQTTnet.Client;
using MQTTnet.Server;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Net;
namespace MQTTnet.Implementations
{
@@ -65,9 +66,22 @@ namespace MQTTnet.Implementations
_socket.Control.KeepAlive = true;
}
string hostName;
string serviceName;
if (_options.RemoteEndpoint is DnsEndPoint dns)
{
hostName = dns.Host;
serviceName = dns.Port.ToString();
}
else
{
throw new NotSupportedException("UWP only supports a DNS endpoint.");
}
if (_options.TlsOptions?.UseTls != true)
{
await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString()).AsTask().ConfigureAwait(false);
await _socket.ConnectAsync(new HostName(hostName), serviceName).AsTask().ConfigureAwait(false);
}
else
{
@@ -88,7 +102,7 @@ namespace MQTTnet.Implementations
socketProtectionLevel = SocketProtectionLevel.Tls10;
}
await _socket.ConnectAsync(new HostName(_options.Server), _options.GetPort().ToString(), socketProtectionLevel).AsTask().ConfigureAwait(false);
await _socket.ConnectAsync(new HostName(hostName), serviceName, socketProtectionLevel).AsTask().ConfigureAwait(false);
}
Endpoint = _socket.Information.RemoteAddress + ":" + _socket.Information.RemotePort;
@@ -5,6 +5,7 @@
#if !WINDOWS_UWP
using System;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Runtime.ExceptionServices;
@@ -92,7 +93,7 @@ namespace MQTTnet.Implementations
socket.DualMode = _tcpOptions.DualMode.Value;
}
await socket.ConnectAsync(_tcpOptions.Server, _tcpOptions.GetPort(), cancellationToken).ConfigureAwait(false);
await socket.ConnectAsync(_tcpOptions.RemoteEndpoint, cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested();
@@ -103,9 +104,11 @@ namespace MQTTnet.Implementations
var targetHost = _tcpOptions.TlsOptions.TargetHost;
if (string.IsNullOrEmpty(targetHost))
{
targetHost = _tcpOptions.Server;
if (_tcpOptions.RemoteEndpoint is DnsEndPoint dns)
{
targetHost = dns.Host;
}
}
var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback);
try
{
+13
View File
@@ -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.Protocol
{
public static class MqttPorts
{
public const int Default = 1883;
public const int Secure = 8883;
}
}