public void DisposeActiveSession()
        {
            lock (_locker)
            {
                if (_activeSession == null)
                {
                    return;
                }

                _tokenSource?.Cancel();

                _activeSession.SessionEnded -= OnSessionEnded;
                _activeSession.Disconnected -= OnSessionDisconnected;
                _activeSession.ReceiveAliveTimeoutOccured -= OnSessionReceiveAliveTimeout;
                _activeSession.ControlStateSetToError     -= OnSessionControlStateSetToError;
                _activeSession.EventOccured -= OnSessionEventOccured;
                _activeSession.DisposeSession();

                _logger.Info("Session with {0}:{1} ended, closed and disposed.",
                             (object)_activeSession.RemoteEndPoint.Address,
                             (object)_activeSession.RemoteEndPoint.Port);

                _activeSession = null;
            }
        }
        public async Task <TLCFIClientSession> GetNewSession(IPEndPoint endPoint, TLCFIClientStateManager stateManager, CancellationToken token)
        {
            if (token.IsCancellationRequested)
            {
                return(null);
            }

            lock (_locker)
            {
                if (_activeSession != null && !_activeSession.Connected)
                {
                    _logger.Warn("A session with {0}:{1} already exists, but is not connected. It will be disposed of.",
                                 _activeSession.RemoteEndPoint.Address, _activeSession.RemoteEndPoint.Port);
                    DisposeActiveSession();
                    return(null);
                }
                if (_activeSession != null)
                {
                    _logger.Warn("There already is a connected session with {0}:{1}. Simultaneous sessions are not allowed.",
                                 _activeSession.RemoteEndPoint.Address, _activeSession.RemoteEndPoint.Port);
                    return(null);
                }
            }

            // Succesful registration interval
            if (DateTime.Now.Subtract(_lastSuccesfulRegister).TotalSeconds < 42)
            {
                var remaining = (int)(42 - DateTime.Now.Subtract(_lastSuccesfulRegister).TotalSeconds) + 1;
                _logger.Info("Need 42 seconds between succesful register calls. Still need to wait {0} seconds. ",
                             remaining);
                await Task.Run(async() =>
                {
                    while (remaining > 0)
                    {
                        await Task.Delay(1000, token);
                        remaining--;
                        if (remaining > 0)
                        {
                            _logger.Trace("Starting new session in {0} seconds.", remaining);
                        }
                    }
                }, token);
            }

            _tokenSource = new CancellationTokenSource();
            var session = new TLCFIClientSession(stateManager, endPoint, _tokenSource.Token);

            _activeSession                      = session;
            session.SessionEnded               += OnSessionEnded;
            session.Disconnected               += OnSessionDisconnected;
            session.ControlStateSetToError     += OnSessionControlStateSetToError;
            session.ReceiveAliveTimeoutOccured += OnSessionReceiveAliveTimeout;
            session.EventOccured               += OnSessionEventOccured;

            var watch = new Stopwatch();

            watch.Reset();

            var sesIp   = endPoint.Address.ToString();
            var sesPort = endPoint.Port.ToString();

            while (!session.Connected)
            {
                try
                {
                    var remaining = _timeout - watch.ElapsedMilliseconds;
                    if (remaining > 0)
                    {
                        await Task.Delay((int)remaining, token);
                    }
                    _tries++;
                    // Backoff procedure
                    if (_tries >= 25)
                    {
                        _timeout = 60000;
                    }
                    else if (_tries >= 21)
                    {
                        _timeout = 30000;
                    }
                    else if (_tries >= 10)
                    {
                        _timeout = 5000;
                    }
                    else if (_tries >= 5)
                    {
                        _timeout = 2000;
                    }
                    watch.Reset();
                    watch.Start();
                    _logger.Info("Connecting to {0}:{1}, try {2}", sesIp, sesPort, _tries);
                    ConnectingStarted?.Invoke(this, _tries);
                    if (token.IsCancellationRequested || _tokenSource.IsCancellationRequested)
                    {
                        return(null);
                    }

                    await session.StartSessionAsync(_timeout);
                }
                catch (TaskCanceledException)
                {
                    return(null);
                }
                catch
                {
                    _logger.Warn("Connecting to {0}:{1} try {2} failed", sesIp, sesPort, _tries);
                    ConnectingFailed?.Invoke(this, _tries);
                }
            }

            _logger.Info("TCP session with {0}:{1} started", sesIp, sesPort);
            TLCSessionStarted?.Invoke(this, session);

            return(session);
        }