Exemplo n.º 1
0
        internal NatsConnection(
            NatsServerInfo serverInfo,
            Socket socket,
            Stream stream,
            CancellationToken cancellationToken)
        {
            ServerInfo = serverInfo ?? throw new ArgumentNullException(nameof(serverInfo));

            _socket = socket ?? throw new ArgumentNullException(nameof(socket));
            if (!socket.Connected)
            {
                throw new ArgumentException("Socket is not connected.", nameof(socket));
            }

            _stream            = stream ?? throw new ArgumentNullException(nameof(stream));
            _writeStream       = new BufferedStream(_stream, socket.SendBufferSize);
            _readStream        = new BufferedStream(_stream, socket.ReceiveBufferSize);
            _cancellationToken = cancellationToken;
            _writeStreamSync   = new SemaphoreSlim(1, 1);
            _writer            = new NatsStreamWriter(_writeStream, _cancellationToken);
            _reader            = new NatsOpStreamReader(_readStream);

            _socketIsConnected = () => _socket?.Connected == true;
            _canRead           = () => _socket?.Connected == true && _stream != null && _stream.CanRead && !_cancellationToken.IsCancellationRequested;
        }
Exemplo n.º 2
0
        private void Dispose(bool disposing)
        {
            if (_isDisposed || !disposing)
            {
                return;
            }

            Try.All(
                () =>
            {
                _readStream?.Dispose();
                _readStream = null;
            },
                () =>
            {
                _writeStream?.Dispose();
                _writeStream = null;
            },
                () =>
            {
                _socket?.Shutdown(SocketShutdown.Both);
                _socket?.Dispose();
                _socket = null;
            },
                () =>
            {
                _writeStreamSync?.Dispose();
                _writeStreamSync = null;
            });

            _reader = null;
            _writer = null;
        }
Exemplo n.º 3
0
        internal NatsConnection(
            NatsServerInfo serverInfo,
            Socket socket,
            BufferedStream writeStream,
            BufferedStream readStream,
            NatsOpStreamReader reader,
            CancellationToken cancellationToken)
        {
            EnsureArg.IsNotNull(serverInfo, nameof(serverInfo));
            EnsureArg.IsNotNull(socket, nameof(socket));
            EnsureArg.IsNotNull(writeStream, nameof(writeStream));
            EnsureArg.IsNotNull(readStream, nameof(readStream));
            EnsureArg.IsNotNull(reader, nameof(reader));

            if (!socket.Connected)
            {
                throw new ArgumentException("Socket is not connected.", nameof(socket));
            }

            ServerInfo = serverInfo;

            _socket            = socket;
            _writeStreamSync   = new Locker();
            _writeStream       = writeStream;
            _readStream        = readStream;
            _reader            = reader;
            _cancellationToken = cancellationToken;

            _writer = new NatsStreamWriter(_writeStream, ServerInfo.MaxPayload, _cancellationToken);

            _socketIsConnected = () => _socket != null && _socket.Connected;
            _canRead           = () => _socketIsConnected() && _readStream != null && _readStream.CanRead && !_cancellationToken.IsCancellationRequested;
        }
Exemplo n.º 4
0
        public void Dispose()
        {
            ThrowIfDisposed();

            _isDisposed = true;

            var exs = new List <Exception>();

            void TryDispose(IDisposable disposable)
            {
                try
                {
                    disposable.Dispose();
                }
                catch (Exception ex)
                {
                    exs.Add(ex);
                }
            }

            TryDispose(_writeStream);
            TryDispose(_readStream);
            TryDispose(_stream);
            try
            {
                _socket.Shutdown(SocketShutdown.Both);
            }
            catch (Exception ex)
            {
                exs.Add(ex);
            }
            TryDispose(_socket);
            TryDispose(_writeStreamSync);

            _writeStream     = null;
            _readStream      = null;
            _stream          = null;
            _socket          = null;
            _writeStreamSync = null;
            _reader          = null;
            _writer          = null;

            if (exs.Any())
            {
                throw new AggregateException("Failed while disposing connection. See inner exception(s) for more details.", exs);
            }
        }
Exemplo n.º 5
0
        private Tuple <INatsConnection, IList <IOp> > EstablishConnection(Host host, ConnectionInfo connectionInfo, CancellationToken cancellationToken)
        {
            Socket         socket      = null;
            BufferedStream writeStream = null;
            BufferedStream readStream  = null;

            try
            {
                socket = _socketFactory.Create(connectionInfo.SocketOptions);

                socket.Connect(
                    host,
                    connectionInfo.SocketOptions.ConnectTimeoutMs,
                    cancellationToken);

                readStream = new BufferedStream(socket.CreateReadStream(), socket.ReceiveBufferSize);

                var reader      = new NatsOpStreamReader(readStream);
                var consumedOps = new List <IOp>();

                IOp ReadOne()
                {
                    var op = reader.ReadOp().FirstOrDefault();

                    if (op != null)
                    {
                        consumedOps.Add(op);
                    }

                    return(op);
                }

                var serverInfo = VerifyConnection(host, connectionInfo, socket, ReadOne);

                writeStream = new BufferedStream(socket.CreateWriteStream(), socket.SendBufferSize);

                return(new Tuple <INatsConnection, IList <IOp> >(new NatsConnection(
                                                                     serverInfo,
                                                                     socket,
                                                                     writeStream,
                                                                     readStream,
                                                                     reader,
                                                                     cancellationToken), consumedOps));
            }
            catch
            {
                Swallow.Everything(
                    () =>
                {
                    readStream?.Dispose();
                    readStream = null;
                },
                    () =>
                {
                    writeStream?.Dispose();
                    writeStream = null;
                },
                    () =>
                {
                    if (socket == null)
                    {
                        return;
                    }

                    if (socket.Connected)
                    {
                        socket.Shutdown(SocketShutdown.Both);
                    }

                    socket.Dispose();
                    socket = null;
                });

                throw;
            }
        }
        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;
            }
        }