Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Client] Fix endpoint handling #1999

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
* [Client] Fix _None of the discovered or specified addresses match the socket address family._ (#1997).
* [Client] Remove the obsolete attribute from the _WithConnectionUri_ methods (#1979).
7 changes: 4 additions & 3 deletions Source/MQTTnet.Tests/Internal/CrossPlatformSocket_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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");
Expand All @@ -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());
Expand Down Expand Up @@ -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;
Expand Down
28 changes: 24 additions & 4 deletions Source/MQTTnet/Client/Options/MqttClientOptionsBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -352,13 +367,18 @@ 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();

// The value 0 will be updated when building the options.
// This a backward compatibility feature.
_remoteEndPoint = new DnsEndPoint(server, port ?? 0);
_remoteEndPoint = new DnsEndPoint(host, port ?? 0, addressFamily);
_port = port;

return this;
Expand Down
7 changes: 7 additions & 0 deletions Source/MQTTnet/Client/Options/MqttClientTcpOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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.Sockets;

Expand All @@ -20,6 +21,12 @@ public sealed class MqttClientTcpOptions : IMqttClientChannelOptions
/// </summary>
public bool? DualMode { get; set; }

[Obsolete("Use RemoteEndpoint or MqttClientOptionsBuilder instead.")]
public int? Port { get; set; }

[Obsolete("Use RemoteEndpoint or MqttClientOptionsBuilder instead.")]
public string Server { get; set; }

public LingerOption LingerState { get; set; } = new LingerOption(true, 0);

/// <summary>
Expand Down
27 changes: 23 additions & 4 deletions Source/MQTTnet/Implementations/CrossPlatformSocket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -202,9 +202,28 @@ public async Task ConnectAsync(EndPoint endPoint, CancellationToken cancellation
using (cancellationToken.Register(_socketDisposeAction))
{
#if NET452 || NET461
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, endPoint, null).ConfigureAwait(false);
// This is a fix for Mono which behaves differently than dotnet.
// The connection will not be established when the DNS endpoint is used.
if (endPoint is DnsEndPoint dns && dns.AddressFamily == AddressFamily.Unspecified)
{
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, dns.Host, dns.Port, null).ConfigureAwait(false);
}
else
{
await Task.Factory.FromAsync(_socket.BeginConnect, _socket.EndConnect, endPoint, null).ConfigureAwait(false);
}
#else
await _socket.ConnectAsync(endPoint).ConfigureAwait(false);

// This is a fix for Mono which behaves differently than dotnet.
// The connection will not be established when the DNS endpoint is used.
if (endPoint is DnsEndPoint dns && dns.AddressFamily == AddressFamily.Unspecified)
{
await _socket.ConnectAsync(dns.Host, dns.Port).ConfigureAwait(false);
}
else
{
await _socket.ConnectAsync(endPoint).ConfigureAwait(false);
}
#endif
}
#endif
Expand Down
26 changes: 25 additions & 1 deletion Source/MQTTnet/Implementations/MqttTcpChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using MQTTnet.Client;
using MQTTnet.Exceptions;
using MQTTnet.Internal;
using MQTTnet.Protocol;

namespace MQTTnet.Implementations
{
Expand Down Expand Up @@ -63,7 +64,7 @@
{
if (_tcpOptions.AddressFamily == AddressFamily.Unspecified)
{
socket = new CrossPlatformSocket();
socket = new CrossPlatformSocket(_tcpOptions.ProtocolType);
}
else
{
Expand Down Expand Up @@ -98,6 +99,29 @@
socket.DualMode = _tcpOptions.DualMode.Value;
}

// This block is only for backward compatibility.
if (_tcpOptions.RemoteEndpoint == null && !string.IsNullOrEmpty(_tcpOptions.Server))

Check warning on line 103 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Server' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 103 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Server' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 103 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Server' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 103 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Server' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'
{
int port;
if (_tcpOptions.Port.HasValue)

Check warning on line 106 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Port' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 106 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Port' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 106 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Port' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 106 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Port' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'
{
port = _tcpOptions.Port.Value;

Check warning on line 108 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Port' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 108 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Port' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 108 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Port' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 108 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Port' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'
}
else
{
if (_tcpOptions.TlsOptions?.UseTls == true)
{
port = MqttPorts.Secure;
}
else
{
port = MqttPorts.Default;
}
}

_tcpOptions.RemoteEndpoint = new DnsEndPoint(_tcpOptions.Server, port, AddressFamily.Unspecified);

Check warning on line 122 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Server' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 122 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Server' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 122 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Server' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'

Check warning on line 122 in Source/MQTTnet/Implementations/MqttTcpChannel.cs

View workflow job for this annotation

GitHub Actions / build

'MqttClientTcpOptions.Server' is obsolete: 'Use RemoteEndpoint or MqttClientOptionsBuilder instead.'
}

await socket.ConnectAsync(_tcpOptions.RemoteEndpoint, cancellationToken).ConfigureAwait(false);

cancellationToken.ThrowIfCancellationRequested();
Expand Down
Loading