public bool Subscribe(Guid correlationId, TcpPackageConnection connection)
        {
            Ensure.NotNull(connection, "connection");

            if (_subscription != null || _unsubscribed != 0)
                return false;

            _correlationId = correlationId;
            connection.EnqueueSend(CreateSubscriptionPackage());
            return true;
        }
        private void HandleTcpPackage(TcpPackageConnection connection, TcpPackage package)
        {
            if (_connection != connection || _state == ConnectionState.Closed || _state == ConnectionState.Init)
            {
                LogDebug("IGNORED: HandleTcpPackage connId {0}, package {1}, {2}.", connection.ConnectionId, package.Command, package.CorrelationId);
                return;
            }
            
            LogDebug("HandleTcpPackage connId {0}, package {1}, {2}.", _connection.ConnectionId, package.Command, package.CorrelationId);
            _packageNumber += 1;

            if (package.Command == TcpCommand.HeartbeatResponseCommand)
                return;
            if (package.Command == TcpCommand.HeartbeatRequestCommand)
            {
                _connection.EnqueueSend(new TcpPackage(TcpCommand.HeartbeatResponseCommand, package.CorrelationId, null));
                return;
            }

            if (package.Command == TcpCommand.Authenticated || package.Command == TcpCommand.NotAuthenticated)
            {
                if (_state == ConnectionState.Connecting
                    && _connectingPhase == ConnectingPhase.Authentication
                    && _authInfo.CorrelationId == package.CorrelationId)
                {
                    if (package.Command == TcpCommand.NotAuthenticated)
                        RaiseAuthenticationFailed("Not authenticated");

                    GoToConnectedState();
                    return;
                }
            }

            if (package.Command == TcpCommand.BadRequest && package.CorrelationId == Guid.Empty)
            {
                string message = Helper.EatException(() => Helper.UTF8NoBom.GetString(package.Data.Array, package.Data.Offset, package.Data.Count));
                var exc = new EventStoreConnectionException(
                        string.Format("Bad request received from server. Error: {0}", string.IsNullOrEmpty(message) ? "<no message>" : message));
                CloseConnection("Connection-wide BadRequest received. Too dangerous to continue.", exc);
                return;
            }

            OperationItem operation;
            SubscriptionItem subscription;
            if (_operations.TryGetActiveOperation(package.CorrelationId, out operation))
            {
                var result = operation.Operation.InspectPackage(package);
                LogDebug("HandleTcpPackage OPERATION DECISION {0} ({1}), {2}", result.Decision, result.Description, operation);
                switch (result.Decision)
                {
                    case InspectionDecision.DoNothing: break; 
                    case InspectionDecision.EndOperation: 
                        _operations.RemoveOperation(operation); 
                        break;
                    case InspectionDecision.Retry: 
                        _operations.ScheduleOperationRetry(operation); 
                        break;
                    case InspectionDecision.Reconnect:
                        ReconnectTo(new NodeEndPoints(result.TcpEndPoint, result.SecureTcpEndPoint));
                        _operations.ScheduleOperationRetry(operation);
                        break;
                    default: throw new Exception(string.Format("Unknown InspectionDecision: {0}", result.Decision));
                }
                if (_state == ConnectionState.Connected)
                    _operations.ScheduleWaitingOperations(connection);
            }
            else if (_subscriptions.TryGetActiveSubscription(package.CorrelationId, out subscription))
            {
                var result = subscription.Operation.InspectPackage(package);
                LogDebug("HandleTcpPackage SUBSCRIPTION DECISION {0} ({1}), {2}", result.Decision, result.Description, subscription);
                switch (result.Decision)
                {
                    case InspectionDecision.DoNothing: break;
                    case InspectionDecision.EndOperation: 
                        _subscriptions.RemoveSubscription(subscription); 
                        break;
                    case InspectionDecision.Retry: 
                        _subscriptions.ScheduleSubscriptionRetry(subscription); 
                        break;
                    case InspectionDecision.Reconnect:
                        ReconnectTo(new NodeEndPoints(result.TcpEndPoint, result.SecureTcpEndPoint));
                        _subscriptions.ScheduleSubscriptionRetry(subscription);
                        break;
                    case InspectionDecision.Subscribed:
                        subscription.IsSubscribed = true;
                        break;
                    default: throw new Exception(string.Format("Unknown InspectionDecision: {0}", result.Decision));
                }
            }
            else
            {
                LogDebug("HandleTcpPackage UNMAPPED PACKAGE with CorrelationId {0:B}, Command: {1}", package.CorrelationId, package.Command);
            }
        }
        private void TcpConnectionEstablished(TcpPackageConnection connection)
        {
            if (_state != ConnectionState.Connecting || _connection != connection || connection.IsClosed)
            {
                LogDebug("IGNORED (_state {0}, _conn.Id {1:B}, conn.Id {2:B}, conn.closed {3}): TCP connection to [{4}, L{5}] established.", 
                         _state, _connection == null ? Guid.Empty : _connection.ConnectionId, connection.ConnectionId, 
                         connection.IsClosed, connection.RemoteEndPoint, connection.LocalEndPoint);
                return;
            }

            LogDebug("TCP connection to [{0}, L{1}, {2:B}] established.", connection.RemoteEndPoint, connection.LocalEndPoint, connection.ConnectionId);
            _heartbeatInfo = new HeartbeatInfo(_packageNumber, true, _stopwatch.Elapsed);

            if (_settings.DefaultUserCredentials != null)
            {
                _connectingPhase = ConnectingPhase.Authentication;

                _authInfo = new AuthInfo(Guid.NewGuid(), _stopwatch.Elapsed);
                _connection.EnqueueSend(new TcpPackage(TcpCommand.Authenticate,
                                                       TcpFlags.Authenticated,
                                                       _authInfo.CorrelationId,
                                                       _settings.DefaultUserCredentials.Username,
                                                       _settings.DefaultUserCredentials.Password, 
                                                       null));
            }
            else
            {
                GoToConnectedState();
            }
        }
        private void TcpConnectionClosed(TcpPackageConnection connection)
        {
            if (_state == ConnectionState.Init) throw new Exception();
            if (_state == ConnectionState.Closed || _connection != connection)
            {
                LogDebug("IGNORED (_state: {0}, _conn.ID: {1:B}, conn.ID: {2:B}): TCP connection to [{3}, L{4}] closed.", 
                         _state, _connection == null ? Guid.Empty : _connection.ConnectionId,  connection.ConnectionId, 
                         connection.RemoteEndPoint, connection.LocalEndPoint);
                return;
            }

            _state = ConnectionState.Connecting;
            _connectingPhase = ConnectingPhase.Reconnecting;

            LogDebug("TCP connection to [{0}, L{1}, {2:B}] closed.", connection.RemoteEndPoint, connection.LocalEndPoint, connection.ConnectionId);

            _subscriptions.PurgeSubscribedAndDroppedSubscriptions(_connection.ConnectionId);
            _reconnInfo = new ReconnectionInfo(_reconnInfo.ReconnectionAttempt, _stopwatch.Elapsed);

            if (Interlocked.CompareExchange(ref _wasConnected, 0, 1) == 1)
            {
                RaiseDisconnected(connection.RemoteEndPoint);
            }
        }
        private void CloseTcpConnection(string reason)
        {
            if (_connection == null)
            {
                LogDebug("CloseTcpConnection IGNORED because _connection == null");
                return;
            }

            LogDebug("CloseTcpConnection");
            _connection.Close(reason);
            TcpConnectionClosed(_connection);
            _connection = null;
        }
        private void TcpConnectionError(TcpPackageConnection connection, Exception exception)
        {
            if (_connection != connection) return;
            if (_state == ConnectionState.Closed) return;

            LogDebug("TcpConnectionError connId {0:B}, exc {1}.", connection.ConnectionId, exception);
            CloseConnection("TCP connection error occurred.", exception);
        }
        private void EstablishTcpConnection(NodeEndPoints endPoints)
        {
            var endPoint = _settings.UseSslConnection ? endPoints.SecureTcpEndPoint ?? endPoints.TcpEndPoint : endPoints.TcpEndPoint;
            if (endPoint == null)
            {
                CloseConnection("No end point to node specified.");
                return;
            }

            LogDebug("EstablishTcpConnection to [{0}]", endPoint);

            if (_state != ConnectionState.Connecting) return;
            if (_connectingPhase != ConnectingPhase.EndPointDiscovery) return;

            _connectingPhase = ConnectingPhase.ConnectionEstablishing;
            _connection = new TcpPackageConnection(
                    _settings.Log,
                    endPoint,
                    Guid.NewGuid(),
                    _settings.UseSslConnection,
                    _settings.TargetHost,
                    _settings.ValidateServer,
                    _settings.ClientConnectionTimeout,
                    (connection, package) => EnqueueMessage(new HandleTcpPackageMessage(connection, package)),
                    (connection, exc) => EnqueueMessage(new TcpConnectionErrorMessage(connection, exc)),
                    connection => EnqueueMessage(new TcpConnectionEstablishedMessage(connection)),
                    (connection, error) => EnqueueMessage(new TcpConnectionClosedMessage(connection, error)));
            _connection.StartReceiving();
        }
        public void CheckTimeoutsAndRetry(TcpPackageConnection connection)
        {
            Ensure.NotNull(connection, "connection");

            var retrySubscriptions = new List<SubscriptionItem>();
            var removeSubscriptions = new List<SubscriptionItem>();
            foreach (var subscription in _activeSubscriptions.Values)
            {
                if (subscription.IsSubscribed) continue;
                if (subscription.ConnectionId != connection.ConnectionId)
                {
                    retrySubscriptions.Add(subscription);
                }
                else if (subscription.Timeout > TimeSpan.Zero && DateTime.UtcNow - subscription.LastUpdated > _settings.OperationTimeout)
                {
                    var err = String.Format("EventStoreConnection '{0}': subscription never got confirmation from server.\n" +
                                            "UTC now: {1:HH:mm:ss.fff}, operation: {2}.",
                                            _connectionName, DateTime.UtcNow, subscription);
                    _settings.Log.Error(err);

                    if (_settings.FailOnNoServerResponse)
                    {
                        subscription.Operation.DropSubscription(SubscriptionDropReason.SubscribingError, new OperationTimedOutException(err));
                        removeSubscriptions.Add(subscription);
                    }
                    else
                    {
                        retrySubscriptions.Add(subscription);
                    }
                }
            }

            foreach (var subscription in retrySubscriptions)
            {
                ScheduleSubscriptionRetry(subscription);
            }
            foreach (var subscription in removeSubscriptions)
            {
                RemoveSubscription(subscription);
            }

            if (_retryPendingSubscriptions.Count > 0)
            {
                foreach (var subscription in _retryPendingSubscriptions)
                {
                    subscription.RetryCount += 1;
                    StartSubscription(subscription, connection);
                }
                _retryPendingSubscriptions.Clear();
            }

            while (_waitingSubscriptions.Count > 0)
            {
                StartSubscription(_waitingSubscriptions.Dequeue(), connection);
            }
        }
        public void StartSubscription(SubscriptionItem subscription, TcpPackageConnection connection)
        {
            Ensure.NotNull(connection, "connection");

            if (subscription.IsSubscribed)
            {
                LogDebug("StartSubscription REMOVING due to already subscribed {0}.", subscription);
                RemoveSubscription(subscription);
                return;
            }

            subscription.CorrelationId = Guid.NewGuid();
            subscription.ConnectionId = connection.ConnectionId;
            subscription.LastUpdated = DateTime.UtcNow;

            _activeSubscriptions.Add(subscription.CorrelationId, subscription);

            if (!subscription.Operation.Subscribe(subscription.CorrelationId, connection))
            {
                LogDebug("StartSubscription REMOVING AS COULDN'T SUBSCRIBE {0}.", subscription);
                RemoveSubscription(subscription);
            }
            else
            {
                LogDebug("StartSubscription SUBSCRIBING {0}.", subscription);
            }
        }
        internal void DropSubscription(SubscriptionDropReason reason, Exception exc, TcpPackageConnection connection = null)
        {
            if (Interlocked.CompareExchange(ref _unsubscribed, 1, 0) == 0)
            {
                if (_verboseLogging)
                    _log.Debug("Subscription {0:B} to {1}: closing subscription, reason: {2}, exception: {3}...",
                               _correlationId, _streamId == string.Empty ? "<all>" : _streamId, reason, exc);

                if (reason != SubscriptionDropReason.UserInitiated)
                {
                    if (exc == null) throw new Exception(string.Format("No exception provided for subscription drop reason '{0}", reason));
                    _source.TrySetException(exc);
                }

                if (reason == SubscriptionDropReason.UserInitiated && _subscription != null && connection != null)
                    connection.EnqueueSend(CreateUnsubscriptionPackage());

                if (_subscription != null)
                    ExecuteActionAsync(() => _subscriptionDropped(_subscription, reason, exc));
            }
        }
Exemple #11
0
 public TcpConnectionClosedMessage(TcpPackageConnection connection, SocketError error)
 {
     Ensure.NotNull(connection, "connection");
     Connection = connection;
     Error = error;
 }
Exemple #12
0
 public TcpConnectionEstablishedMessage(TcpPackageConnection connection)
 {
     Ensure.NotNull(connection, "connection");
     Connection = connection;
 }
Exemple #13
0
 public TcpConnectionErrorMessage(TcpPackageConnection connection, Exception exception)
 {
     Connection = connection;
     Exception = exception;
 }
Exemple #14
0
 public HandleTcpPackageMessage(TcpPackageConnection connection, TcpPackage package)
 {
     Connection = connection;
     Package = package;
 }