public bool Start(bool treatErrorsAsWarning, CancellationToken cancellationToken) { try { var boundIp = _options.BoundInterNetworkAddress; if (_addressFamily == AddressFamily.InterNetworkV6) { boundIp = _options.BoundInterNetworkV6Address; } _localEndPoint = new IPEndPoint(boundIp, _options.Port); _logger.Info("Starting TCP listener (Endpoint='{0}', TLS={1}).", _localEndPoint, _tlsCertificate != null); _socket = new CrossPlatformSocket(_addressFamily); // Usage of socket options is described here: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.setsocketoption?view=netcore-2.2 if (_options.ReuseAddress) { _socket.ReuseAddress = true; } if (_options.NoDelay) { _socket.NoDelay = true; } if (_options.LingerState != null) { _socket.LingerState = _options.LingerState; } _socket.Bind(_localEndPoint); // Get the local endpoint back from the socket. The port may have changed. // This can happen when port 0 is used. Then the OS will choose the next free port. _localEndPoint = (IPEndPoint)_socket.LocalEndPoint; _options.Port = _localEndPoint.Port; _socket.Listen(_options.ConnectionBacklog); _logger.Verbose("TCP listener started (Endpoint='{0}'.", _localEndPoint); Task.Run(() => AcceptClientConnectionsAsync(cancellationToken), cancellationToken).RunInBackground(_logger); return(true); } catch (Exception exception) { if (!treatErrorsAsWarning) { throw; } _logger.Warning(exception, "Error while creating listener socket for local end point '{0}'.", _localEndPoint); return(false); } }
public async Task ConnectAsync(CancellationToken cancellationToken) { CrossPlatformSocket socket; if (_options.AddressFamily == AddressFamily.Unspecified) { socket = new CrossPlatformSocket(); } else { socket = new CrossPlatformSocket(_options.AddressFamily); } socket.ReceiveBufferSize = _options.BufferSize; socket.SendBufferSize = _options.BufferSize; socket.NoDelay = _options.NoDelay; if (_options.DualMode.HasValue) { // 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 // of the actual value. socket.DualMode = _options.DualMode.Value; } await socket.ConnectAsync(_options.Server, _options.GetPort(), cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); var networkStream = socket.GetStream(); if (_options.TlsOptions?.UseTls == true) { var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback); try { await sslStream.AuthenticateAsClientAsync(_options.Server, LoadCertificates(), _options.TlsOptions.SslProtocol, !_options.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); } catch { sslStream.Dispose(); throw; } _stream = sslStream; } else { _stream = networkStream; } Endpoint = socket.RemoteEndPoint?.ToString(); }
#pragma warning disable 4014 public bool Start(bool treatErrorsAsWarning, CancellationToken cancellationToken) { try { var boundIp = _options.BoundInterNetworkAddress; if (_addressFamily == AddressFamily.InterNetworkV6) { boundIp = _options.BoundInterNetworkV6Address; } _localEndPoint = new IPEndPoint(boundIp, _options.Port); _logger.Info($"Starting TCP listener for {_localEndPoint} TLS={_tlsCertificate != null}."); _socket = new CrossPlatformSocket(_addressFamily); // Usage of socket options is described here: https://docs.microsoft.com/en-us/dotnet/api/system.net.sockets.socket.setsocketoption?view=netcore-2.2 if (_options.ReuseAddress) { _socket.ReuseAddress = true; } if (_options.NoDelay) { _socket.NoDelay = true; } _socket.Bind(_localEndPoint); _socket.Listen(_options.ConnectionBacklog); #if NET40 TaskExtension.Run(() => AcceptClientConnectionsAsync(cancellationToken).Wait(), cancellationToken).Forget(_logger); #else TaskExtension.Run(() => AcceptClientConnectionsAsync(cancellationToken), cancellationToken).Forget(_logger); #endif return(true); } catch (Exception exception) { if (!treatErrorsAsWarning) { throw; } _logger.Warning(exception, "Error while creating listener socket for local end point '{0}'.", _localEndPoint); return(false); } }
public async Task ConnectAsync(CancellationToken cancellationToken) { CrossPlatformSocket socket = null; try { if (_tcpOptions.AddressFamily == AddressFamily.Unspecified) { socket = new CrossPlatformSocket(); } else { socket = new CrossPlatformSocket(_tcpOptions.AddressFamily); } socket.ReceiveBufferSize = _tcpOptions.BufferSize; socket.SendBufferSize = _tcpOptions.BufferSize; socket.SendTimeout = (int)_clientOptions.Timeout.TotalMilliseconds; socket.NoDelay = _tcpOptions.NoDelay; if (socket.LingerState != null) { socket.LingerState = _tcpOptions.LingerState; } if (_tcpOptions.DualMode.HasValue) { // 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 // of the actual value. socket.DualMode = _tcpOptions.DualMode.Value; } await socket.ConnectAsync(_tcpOptions.Server, _tcpOptions.GetPort(), cancellationToken).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); var networkStream = socket.GetStream(); if (_tcpOptions.TlsOptions?.UseTls == true) { var sslStream = new SslStream(networkStream, false, InternalUserCertificateValidationCallback); try { #if NETCOREAPP3_1 || NET5_0_OR_GREATER var sslOptions = new SslClientAuthenticationOptions { ApplicationProtocols = _tcpOptions.TlsOptions.ApplicationProtocols, ClientCertificates = LoadCertificates(), EnabledSslProtocols = _tcpOptions.TlsOptions.SslProtocol, CertificateRevocationCheckMode = _tcpOptions.TlsOptions.IgnoreCertificateRevocationErrors ? X509RevocationMode.NoCheck : X509RevocationMode.Online, TargetHost = _tcpOptions.Server }; await sslStream.AuthenticateAsClientAsync(sslOptions, cancellationToken).ConfigureAwait(false); #else await sslStream.AuthenticateAsClientAsync(_tcpOptions.Server, LoadCertificates(), _tcpOptions.TlsOptions.SslProtocol, !_tcpOptions.TlsOptions.IgnoreCertificateRevocationErrors).ConfigureAwait(false); #endif } catch { #if NETSTANDARD2_1 || NETCOREAPP3_1 || NET5_0_OR_GREATER await sslStream.DisposeAsync().ConfigureAwait(false); #else sslStream.Dispose(); #endif throw; } _stream = sslStream; } else { _stream = networkStream; } Endpoint = socket.RemoteEndPoint?.ToString(); } catch (Exception) { socket?.Dispose(); throw; } }
async Task TryHandleClientConnectionAsync(CrossPlatformSocket clientSocket) { Stream stream = null; string remoteEndPoint = null; try { remoteEndPoint = clientSocket.RemoteEndPoint.ToString(); _logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.", remoteEndPoint, _localEndPoint, _addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); clientSocket.NoDelay = _options.NoDelay; stream = clientSocket.GetStream(); X509Certificate2 clientCertificate = null; if (_tlsCertificate != null) { var sslStream = new SslStream(stream, false, _tlsOptions.RemoteCertificateValidationCallback); await sslStream.AuthenticateAsServerAsync( _tlsCertificate, _tlsOptions.ClientCertificateRequired, _tlsOptions.SslProtocol, _tlsOptions.CheckCertificateRevocation).ConfigureAwait(false); stream = sslStream; clientCertificate = sslStream.RemoteCertificate as X509Certificate2; if (clientCertificate == null && sslStream.RemoteCertificate != null) { clientCertificate = new X509Certificate2(sslStream.RemoteCertificate.Export(X509ContentType.Cert)); } } var clientHandler = ClientHandler; if (clientHandler != null) { using (var clientAdapter = new MqttChannelAdapter( new MqttTcpChannel(stream, remoteEndPoint, clientCertificate), new MqttPacketFormatterAdapter(new MqttPacketWriter()), null, _rootLogger)) { await clientHandler(clientAdapter).ConfigureAwait(false); } } } catch (Exception exception) { if (exception is ObjectDisposedException) { // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. return; } if (exception is SocketException socketException && socketException.SocketErrorCode == SocketError.OperationAborted) { return; } _logger.Error(exception, "Error while handling client connection."); } finally { try { stream?.Dispose(); clientSocket?.Dispose(); } catch (Exception disposeException) { _logger.Error(disposeException, "Error while cleaning up client connection"); } } _logger.Verbose("Client '{0}' disconnected at TCP listener '{1}, {2}'.", remoteEndPoint, _localEndPoint, _addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); }
async Task TryHandleClientConnectionAsync(CrossPlatformSocket clientSocket) { Stream stream = null; string remoteEndPoint = null; try { remoteEndPoint = clientSocket.RemoteEndPoint.ToString(); _logger.Verbose("Client '{0}' accepted by TCP listener '{1}, {2}'.", remoteEndPoint, _localEndPoint, _addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); clientSocket.NoDelay = _options.NoDelay; stream = clientSocket.GetStream(); X509Certificate2 clientCertificate = null; if (_tlsCertificate != null) { var sslStream = new SslStream(stream, false, _tlsOptions.RemoteCertificateValidationCallback); #if NETCOREAPP3_1 || NET5_0_OR_GREATER await sslStream.AuthenticateAsServerAsync( new SslServerAuthenticationOptions() { ServerCertificate = _tlsCertificate, ClientCertificateRequired = _tlsOptions.ClientCertificateRequired, EnabledSslProtocols = _tlsOptions.SslProtocol, CertificateRevocationCheckMode = _tlsOptions.CheckCertificateRevocation ? X509RevocationMode.Online : X509RevocationMode.NoCheck, EncryptionPolicy = EncryptionPolicy.RequireEncryption, CipherSuitesPolicy = _tlsOptions.CipherSuitesPolicy }).ConfigureAwait(false); #else await sslStream.AuthenticateAsServerAsync( _tlsCertificate, _tlsOptions.ClientCertificateRequired, _tlsOptions.SslProtocol, _tlsOptions.CheckCertificateRevocation).ConfigureAwait(false); #endif stream = sslStream; clientCertificate = sslStream.RemoteCertificate as X509Certificate2; if (clientCertificate == null && sslStream.RemoteCertificate != null) { clientCertificate = new X509Certificate2(sslStream.RemoteCertificate.Export(X509ContentType.Cert)); } } var clientHandler = ClientHandler; if (clientHandler != null) { var tcpChannel = new MqttTcpChannel(stream, remoteEndPoint, clientCertificate); var bufferWriter = new MqttBufferWriter(_serverOptions.WriterBufferSize, _serverOptions.WriterBufferSizeMax); var packetFormatterAdapter = new MqttPacketFormatterAdapter(bufferWriter); using (var clientAdapter = new MqttChannelAdapter(tcpChannel, packetFormatterAdapter, null, _rootLogger)) { await clientHandler(clientAdapter).ConfigureAwait(false); } } } catch (Exception exception) { if (exception is ObjectDisposedException) { // It can happen that the listener socket is accessed after the cancellation token is already set and the listener socket is disposed. return; } if (exception is SocketException socketException && socketException.SocketErrorCode == SocketError.OperationAborted) { return; } _logger.Error(exception, "Error while handling client connection."); } finally { try { stream?.Dispose(); clientSocket?.Dispose(); } catch (Exception disposeException) { _logger.Error(disposeException, "Error while cleaning up client connection"); } } _logger.Verbose("Client '{0}' disconnected at TCP listener '{1}, {2}'.", remoteEndPoint, _localEndPoint, _addressFamily == AddressFamily.InterNetwork ? "ipv4" : "ipv6"); }