Expose local endpoint in channel adapter (#2213)

* Expose local endpoint

* Update release notes
This commit is contained in:
Christian
2025-10-19 23:06:36 +02:00
committed by GitHub
parent 5ebc5fcb7e
commit e791d9aba4
14 changed files with 208 additions and 150 deletions
@@ -22,6 +22,8 @@ public interface IMqttChannelAdapter : IDisposable
EndPoint RemoteEndPoint { get; }
EndPoint LocalEndPoint { get; }
bool IsSecureConnection { get; }
MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
@@ -54,6 +54,8 @@ public sealed class MqttChannelAdapter : Disposable, IMqttChannelAdapter
public EndPoint RemoteEndPoint => _channel.RemoteEndPoint;
public EndPoint LocalEndPoint => _channel.LocalEndPoint;
public bool IsSecureConnection => _channel.IsSecureConnection;
public MqttPacketFormatterAdapter PacketFormatterAdapter { get; }
+3
View File
@@ -14,8 +14,11 @@ namespace MQTTnet.Channel;
public interface IMqttChannel : IDisposable
{
X509Certificate2 ClientCertificate { get; }
EndPoint RemoteEndPoint { get; }
EndPoint LocalEndPoint { get; }
bool IsSecureConnection { get; }
Task ConnectAsync(CancellationToken cancellationToken);
@@ -37,10 +37,11 @@ public sealed class MqttTcpChannel : IMqttChannel
IsSecureConnection = clientOptions.ChannelOptions?.TlsOptions?.UseTls == true;
}
public MqttTcpChannel(Stream stream, EndPoint remoteEndPoint, X509Certificate2 clientCertificate) : this()
public MqttTcpChannel(Stream stream, EndPoint localEndPoint, EndPoint remoteEndPoint, X509Certificate2 clientCertificate) : this()
{
_stream = stream ?? throw new ArgumentNullException(nameof(stream));
LocalEndPoint = localEndPoint;
RemoteEndPoint = remoteEndPoint;
IsSecureConnection = stream is SslStream;
@@ -49,10 +50,13 @@ public sealed class MqttTcpChannel : IMqttChannel
public X509Certificate2 ClientCertificate { get; }
public EndPoint RemoteEndPoint { get; private set; }
public bool IsSecureConnection { get; }
public EndPoint LocalEndPoint { get; private set; }
public EndPoint RemoteEndPoint { get; private set; }
public async Task ConnectAsync(CancellationToken cancellationToken)
{
CrossPlatformSocket socket = null;
@@ -87,7 +91,7 @@ public sealed class MqttTcpChannel : IMqttChannel
socket.LingerState = _tcpOptions.LingerState;
}
if (_tcpOptions.DualMode.HasValue)
if (_tcpOptions.DualMode != null)
{
// It is important to avoid setting the flag if no specific value is set by the user
// because on IPv4 only networks the setter will always throw an exception. Regardless
@@ -115,37 +119,20 @@ public sealed class MqttTcpChannel : IMqttChannel
SslStream sslStream;
if (_tcpOptions.TlsOptions.CertificateSelectionHandler != null)
{
sslStream = new SslStream(
networkStream,
false,
InternalUserCertificateValidationCallback,
InternalUserCertificateSelectionCallback);
sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback, InternalUserCertificateSelectionCallback);
}
else
{
// Use a different constructor depending on the options for MQTTnet so that we do not have
// to copy the exact same behavior of the selection handler.
sslStream = new SslStream(
networkStream,
false,
InternalUserCertificateValidationCallback);
sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback);
}
try
{
var sslOptions = new SslClientAuthenticationOptions
{
ApplicationProtocols = _tcpOptions.TlsOptions.ApplicationProtocols,
ClientCertificates = LoadCertificates(),
EnabledSslProtocols = _tcpOptions.TlsOptions.SslProtocol,
CertificateRevocationCheckMode = _tcpOptions.TlsOptions.IgnoreCertificateRevocationErrors
? X509RevocationMode.NoCheck
: _tcpOptions.TlsOptions.RevocationMode,
TargetHost = targetHost,
CipherSuitesPolicy = _tcpOptions.TlsOptions.CipherSuitesPolicy,
EncryptionPolicy = _tcpOptions.TlsOptions.EncryptionPolicy,
AllowRenegotiation = _tcpOptions.TlsOptions.AllowRenegotiation
};
var sslOptions = CreateSslAuthenticationOptions();
sslOptions.TargetHost = targetHost;
if (_tcpOptions.TlsOptions.TrustChain?.Count > 0)
{
@@ -176,6 +163,7 @@ public sealed class MqttTcpChannel : IMqttChannel
}
RemoteEndPoint = socket.RemoteEndPoint;
LocalEndPoint = socket.LocalEndPoint;
}
catch
{
@@ -281,6 +269,21 @@ public sealed class MqttTcpChannel : IMqttChannel
}
}
SslClientAuthenticationOptions CreateSslAuthenticationOptions()
{
var sslOptions = new SslClientAuthenticationOptions
{
ApplicationProtocols = _tcpOptions.TlsOptions.ApplicationProtocols,
ClientCertificates = LoadCertificates(),
EnabledSslProtocols = _tcpOptions.TlsOptions.SslProtocol,
CertificateRevocationCheckMode = _tcpOptions.TlsOptions.IgnoreCertificateRevocationErrors ? X509RevocationMode.NoCheck : _tcpOptions.TlsOptions.RevocationMode,
CipherSuitesPolicy = _tcpOptions.TlsOptions.CipherSuitesPolicy,
EncryptionPolicy = _tcpOptions.TlsOptions.EncryptionPolicy,
AllowRenegotiation = _tcpOptions.TlsOptions.AllowRenegotiation
};
return sslOptions;
}
X509Certificate InternalUserCertificateSelectionCallback(
object sender,
string targetHost,
@@ -39,6 +39,8 @@ public sealed class MqttWebSocketChannel : IMqttChannel
public EndPoint RemoteEndPoint { get; }
public EndPoint LocalEndPoint { get; }
public bool IsSecureConnection { get; private set; }
public async Task ConnectAsync(CancellationToken cancellationToken)