From 3da940d9f07f3e3411958fc43fe39a48e3139f36 Mon Sep 17 00:00:00 2001 From: christian <6939810+chkr1011@users.noreply.github.com> Date: Fri, 17 May 2024 17:04:08 +0200 Subject: [PATCH] Fix endpoint handling --- .github/workflows/ReleaseNotes.md | 15 +------ .../Internal/CrossPlatformSocket_Tests.cs | 7 ++-- .../Options/MqttClientOptionsBuilder.cs | 41 ++++++++++++++++--- .../Implementations/CrossPlatformSocket.cs | 4 +- .../MQTTnet/Implementations/MqttTcpChannel.cs | 2 +- 5 files changed, 44 insertions(+), 25 deletions(-) diff --git a/.github/workflows/ReleaseNotes.md b/.github/workflows/ReleaseNotes.md index 1016e556a..8123cd240 100644 --- a/.github/workflows/ReleaseNotes.md +++ b/.github/workflows/ReleaseNotes.md @@ -1,13 +1,2 @@ -* [Core] Optimized packet serialization of PUBACK and PUBREC packets for protocol version 5.0.0 (#1939, thanks to @Y-Sindo). -* [Core] The package inspector is now fully async (#1941). -* [Core] Fixed decoding of DISCONNECT packet with empty body (#1994, thanks to @Y-Sindo). -* [Client] Exposed the _EndPoint_ type to support other endpoint types (like Unix Domain Sockets) in client options (#1919). -* [Client] Fixed support for unix sockets by exposing more options (#1995). -* [Client] Added a dedicated exception when the client is not connected (#1954, thanks to @marcpiulachs). -* [Client] The client will now throw a _MqttClientUnexpectedDisconnectReceivedException_ when publishing a QoS 0 message which leads to a server disconnect (BREAKING CHANGE!, #1974, thanks to @fazho). -* [Client] Exposed the certificate selection event handler in client options (#1984). -* [Server] The server will no longer send _NoMatchingSubscribers_ when the actual subscription was non success (#1965, BREAKING CHANGE!). -* [Server] Fixed broken support for _null_ in _AddServer_ method in ASP.NET integration (#1981). -* [ManagedClient] Added a new event (SubscriptionsChangedAsync) which is fired when a subscription or unsubscription was made (#1894, thanks to @pdufrene). -* [ManagedClient] Fixed race condition when server shuts down while subscribing (#1987, thanks to @marve). -* [TopicTemplate] Added new extension which provides a template engine for topics (#1932, thanks to @simonthum). +* [Client] Fix _None of the discovered or specified addresses match the socket address family._ (#1997). + diff --git a/Source/MQTTnet.Tests/Internal/CrossPlatformSocket_Tests.cs b/Source/MQTTnet.Tests/Internal/CrossPlatformSocket_Tests.cs index 1c2ecdf10..034991781 100644 --- a/Source/MQTTnet.Tests/Internal/CrossPlatformSocket_Tests.cs +++ b/Source/MQTTnet.Tests/Internal/CrossPlatformSocket_Tests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -17,7 +18,7 @@ public class CrossPlatformSocket_Tests [TestMethod] public async Task Connect_Send_Receive() { - var crossPlatformSocket = new CrossPlatformSocket(); + var crossPlatformSocket = new CrossPlatformSocket(ProtocolType.Tcp); await crossPlatformSocket.ConnectAsync("www.google.de", 80, CancellationToken.None); var requestBuffer = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\nHost: www.google.de\r\n\r\n"); @@ -36,7 +37,7 @@ public async Task Connect_Send_Receive() [ExpectedException(typeof(OperationCanceledException))] public async Task Try_Connect_Invalid_Host() { - var crossPlatformSocket = new CrossPlatformSocket(); + var crossPlatformSocket = new CrossPlatformSocket(ProtocolType.Tcp); var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(5)); cancellationToken.Token.Register(() => crossPlatformSocket.Dispose()); @@ -65,7 +66,7 @@ public async Task Try_Connect_Invalid_Host() [TestMethod] public void Set_Options() { - var crossPlatformSocket = new CrossPlatformSocket(); + var crossPlatformSocket = new CrossPlatformSocket(ProtocolType.Tcp); Assert.IsFalse(crossPlatformSocket.ReuseAddress); crossPlatformSocket.ReuseAddress = true; diff --git a/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs b/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs index f89f9f2d4..4663ac62b 100644 --- a/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs +++ b/Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs @@ -79,11 +79,26 @@ public MqttClientOptions Build() { if (_port.HasValue) { - _remoteEndPoint = new DnsEndPoint(dns.Host, _port.Value); + _remoteEndPoint = new DnsEndPoint(dns.Host, _port.Value, dns.AddressFamily); } else { - _remoteEndPoint = new DnsEndPoint(dns.Host, tlsOptions?.UseTls == false ? MqttPorts.Default : MqttPorts.Secure); + _remoteEndPoint = new DnsEndPoint(dns.Host, tlsOptions?.UseTls == false ? MqttPorts.Default : MqttPorts.Secure, dns.AddressFamily); + } + } + } + + if (_remoteEndPoint is IPEndPoint ip) + { + if (ip.Port == 0) + { + if (_port.HasValue) + { + _remoteEndPoint = new IPEndPoint(ip.Address, _port.Value); + } + else + { + _remoteEndPoint = new IPEndPoint(ip.Address, tlsOptions?.UseTls == false ? MqttPorts.Default : MqttPorts.Secure); } } } @@ -152,7 +167,6 @@ public MqttClientOptionsBuilder WithClientId(string value) return this; } - [Obsolete("Use WithTcpServer(... configure) or WithWebSocketServer(... configure) instead.")] public MqttClientOptionsBuilder WithConnectionUri(Uri uri) { if (uri == null) @@ -196,7 +210,6 @@ public MqttClientOptionsBuilder WithConnectionUri(Uri uri) return this; } - [Obsolete("Use WithTcpServer(... configure) or WithWebSocketServer(... configure) instead.")] public MqttClientOptionsBuilder WithConnectionUri(string uri) { return WithConnectionUri(new Uri(uri, UriKind.Absolute)); @@ -354,13 +367,29 @@ public MqttClientOptionsBuilder WithSessionExpiryInterval(uint sessionExpiryInte return this; } - public MqttClientOptionsBuilder WithTcpServer(string server, int? port = null) + public MqttClientOptionsBuilder WithTcpServer(string host, int? port = null, AddressFamily addressFamily = AddressFamily.Unspecified) { + if (host == null) + { + throw new ArgumentNullException(nameof(host)); + } + _tcpOptions = new MqttClientTcpOptions(); + _port = port; + // The value 0 will be updated when building the options. // This a backward compatibility feature. - _remoteEndPoint = new DnsEndPoint(server, port ?? 0); + + if (IPAddress.TryParse(host, out var ipAddress)) + { + _remoteEndPoint = new IPEndPoint(ipAddress, port ?? 0); + } + else + { + _remoteEndPoint = new DnsEndPoint(host, port ?? 0, addressFamily); + } + _port = port; return this; diff --git a/Source/MQTTnet/Implementations/CrossPlatformSocket.cs b/Source/MQTTnet/Implementations/CrossPlatformSocket.cs index c3d29c169..202be6059 100644 --- a/Source/MQTTnet/Implementations/CrossPlatformSocket.cs +++ b/Source/MQTTnet/Implementations/CrossPlatformSocket.cs @@ -31,11 +31,11 @@ public CrossPlatformSocket(AddressFamily addressFamily, ProtocolType protocolTyp #endif } - public CrossPlatformSocket() + public CrossPlatformSocket(ProtocolType protocolType) { // Having this constructor is important because avoiding the address family as parameter // will make use of dual mode in the .net framework. - _socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + _socket = new Socket(SocketType.Stream, protocolType); #if !NET5_0_OR_GREATER _socketDisposeAction = _socket.Dispose; diff --git a/Source/MQTTnet/Implementations/MqttTcpChannel.cs b/Source/MQTTnet/Implementations/MqttTcpChannel.cs index a5108e586..cbce5f39f 100644 --- a/Source/MQTTnet/Implementations/MqttTcpChannel.cs +++ b/Source/MQTTnet/Implementations/MqttTcpChannel.cs @@ -63,7 +63,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken) { if (_tcpOptions.AddressFamily == AddressFamily.Unspecified) { - socket = new CrossPlatformSocket(); + socket = new CrossPlatformSocket(_tcpOptions.ProtocolType); } else {