private static NatsServerInfo VerifyConnection(Host host, ConnectionInfo connectionInfo, Socket socket, Func <IOp> readOne) { if (!socket.Connected) { throw NatsException.FailedToConnectToHost(host, "No connection could be established."); } var op = readOne(); if (op == null) { throw NatsException.FailedToConnectToHost(host, "Expected to get INFO after establishing connection. Got nothing."); } var infoOp = op as InfoOp; if (infoOp == null) { throw NatsException.FailedToConnectToHost(host, $"Expected to get INFO after establishing connection. Got {op.GetType().Name}."); } Logger.Debug($"Got INFO during connect. {infoOp.GetAsString()}"); var serverInfo = NatsServerInfo.Parse(infoOp.Message); var credentials = host.HasNonEmptyCredentials() ? host.Credentials : connectionInfo.Credentials; if (serverInfo.AuthRequired && (credentials == null || credentials == Credentials.Empty)) { throw NatsException.MissingCredentials(host); } socket.Send(ConnectCmd.Generate(connectionInfo.Verbose, credentials)); socket.Send(PingCmd.Generate()); op = readOne(); if (op == null) { throw NatsException.FailedToConnectToHost(host, "Expected to read something after CONNECT and PING. Got nothing."); } if (op is ErrOp) { throw NatsException.FailedToConnectToHost(host, $"Expected to get PONG after sending CONNECT and PING. Got {op.GetAsString()}."); } if (!socket.Connected) { throw NatsException.FailedToConnectToHost(host, "No connection could be established."); } return(serverInfo); }
private async Task <(INatsConnection connection, IList <IOp> consumedOps)> EstablishConnectionAsync( Host host, ConnectionInfo connectionInfo, CancellationToken cancellationToken) { var serverCertificateValidation = connectionInfo.ServerCertificateValidation ?? DefaultServerCertificateValidation; bool RemoteCertificateValidationCallback(object _, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) => serverCertificateValidation(certificate, chain, errors); var consumedOps = new List <IOp>(); Socket socket = null; Stream stream = null; try { socket = _socketFactory.Create(connectionInfo.SocketOptions); await socket.ConnectAsync( host, connectionInfo.SocketOptions.ConnectTimeoutMs, cancellationToken).ConfigureAwait(false); stream = socket.CreateReadWriteStream(); var reader = new NatsOpStreamReader(stream); var op = reader.ReadOneOp(); if (op == null) { throw NatsException.FailedToConnectToHost(host, "Expected to get INFO after establishing connection. Got nothing."); } if (!(op is InfoOp infoOp)) { throw NatsException.FailedToConnectToHost(host, $"Expected to get INFO after establishing connection. Got {op.GetType().Name}."); } var serverInfo = NatsServerInfo.Parse(infoOp.Message); var credentials = host.HasNonEmptyCredentials() ? host.Credentials : connectionInfo.Credentials; if (serverInfo.AuthRequired && (credentials == null || credentials == Credentials.Empty)) { throw NatsException.MissingCredentials(host); } if (serverInfo.TlsVerify && connectionInfo.ClientCertificates.Count == 0) { throw NatsException.MissingClientCertificates(host); } consumedOps.Add(op); if (serverInfo.TlsRequired) { await stream.DisposeAsync(); stream = new SslStream(socket.CreateReadWriteStream(), false, RemoteCertificateValidationCallback, null, EncryptionPolicy.RequireEncryption); var ssl = (SslStream)stream; var clientAuthOptions = new SslClientAuthenticationOptions { RemoteCertificateValidationCallback = RemoteCertificateValidationCallback, AllowRenegotiation = true, CertificateRevocationCheckMode = X509RevocationMode.Online, ClientCertificates = connectionInfo.ClientCertificates, EnabledSslProtocols = SslProtocols.Tls12, EncryptionPolicy = EncryptionPolicy.RequireEncryption, TargetHost = host.Address }; await ssl.AuthenticateAsClientAsync(clientAuthOptions, cancellationToken).ConfigureAwait(false); reader = new NatsOpStreamReader(ssl); } stream.Write(ConnectCmd.Generate(connectionInfo.Verbose, credentials, connectionInfo.Name)); stream.Write(PingCmd.Bytes.Span); await stream.FlushAsync(cancellationToken).ConfigureAwait(false); op = reader.ReadOneOp(); if (op == null) { throw NatsException.FailedToConnectToHost(host, "Expected to read something after CONNECT and PING. Got nothing."); } if (op is ErrOp) { throw NatsException.FailedToConnectToHost(host, $"Expected to get PONG after sending CONNECT and PING. Got {op.GetAsString()}."); } if (!socket.Connected) { throw NatsException.FailedToConnectToHost(host, "No connection could be established."); } consumedOps.Add(op); return( new NatsConnection( serverInfo, socket, stream, cancellationToken), consumedOps); } catch { Swallow.Everything( () => { stream?.Dispose(); stream = null; }, () => { if (socket == null) { return; } if (socket.Connected) { socket.Shutdown(SocketShutdown.Both); } socket.Dispose(); socket = null; }); throw; } }