Exemplo n.º 1
0
        /// <summary>
        /// Handles the failed state of the session
        /// </summary>
        /// <param name="id"></param>
        /// <param name="wrapper"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private async Task HandleFailedAsync(ConnectionIdentifier id,
                                             SessionWrapper wrapper, CancellationToken ct)
        {
            try {
                // check if session requires cleanup
                if (!wrapper._subscriptions.Any())
                {
                    if (wrapper.IdleCount < wrapper.MaxKeepAlives)
                    {
                        wrapper.IdleCount++;
                    }
                    else
                    {
                        _logger.Information("Session '{id}' set to disconnect in {state}",
                                            id, wrapper.State);
                        wrapper.State = SessionState.Disconnect;
                        await HandleDisconnectAsync(id, wrapper).ConfigureAwait(false);

                        return;
                    }
                }
                else
                {
                    wrapper.IdleCount = 0;
                }
                if (!ct.IsCancellationRequested)
                {
                    await HandleInitAsync(id, wrapper, ct).ConfigureAwait(false);
                }
            }
            catch (Exception ex) {
                _logger.Error(ex, "Failed to reinitiate failed session");
            }
        }
Exemplo n.º 2
0
        /// <inheritdoc/>
        public ISessionHandle GetSessionHandle(ConnectionModel connection)
        {
            if (connection?.Endpoint == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            var id = new ConnectionIdentifier(connection);

            _lock.Wait();
            try {
                // Add a persistent session
                if (!_clients.TryGetValue(id, out var client))
                {
                    var tuple = ClientSession.CreateWithHandle(_appConfig,
                                                               id.Connection, _logger, NotifyStateChangeAsync, _maxOpTimeout);
                    _clients.Add(id, tuple.Item1);
                    _logger.Debug("Opened session for endpoint {id} ({endpoint}).",
                                  id, connection.Endpoint.Url);
                    return(tuple.Item2);
                }
                return(client.GetSafeHandle());
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 3
0
        /// <inheritdoc/>
        public void RegisterSubscription(ISubscription subscription)
        {
            var id = new ConnectionIdentifier(subscription.Connection);

            _lock.Wait();
            try {
                if (!_sessions.TryGetValue(id, out var wrapper))
                {
                    wrapper = new SessionWrapper()
                    {
                        Id = id.ToString(),
                        MissedKeepAlives = 0,
                        MaxKeepAlives    = (int)_clientConfig.MaxKeepAliveCount,
                        State            = SessionState.Init,
                        Session          = null,
                        IdleCount        = 0
                    };
                    _sessions.AddOrUpdate(id, wrapper);
                }
                wrapper._subscriptions.AddOrUpdate(subscription.Id, subscription);
                _logger.Information("Subscription '{subscriptionId}' registered/updated in session '{id}' in state {state}",
                                    subscription.Id, id, wrapper.State);
                if (wrapper.State == SessionState.Running)
                {
                    wrapper.State = SessionState.Refresh;
                }
                TriggerKeepAlive();
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Handles the disconnect state of a session
        /// </summary>
        /// <param name="id"></param>
        /// <param name="wrapper"></param>
        /// <returns></returns>
        private async Task HandleDisconnectAsync(ConnectionIdentifier id, SessionWrapper wrapper)
        {
            _logger.Debug("Removing session '{id}'", id);
            await _lock.WaitAsync().ConfigureAwait(false);

            try {
                _sessions.Remove(id, out _);
            }
            finally {
                _lock.Release();
            }
            try {
                if (wrapper != null && wrapper.Session != null)
                {
                    wrapper.Session.Handle = null;
                    // Remove subscriptions
                    if (wrapper.Session.SubscriptionCount > 0)
                    {
                        foreach (var subscription in wrapper.Session.Subscriptions)
                        {
                            Try.Op(() => subscription.DeleteItems());
                        }
                        Try.Op(() => wrapper.Session.RemoveSubscriptions(wrapper.Session.Subscriptions));
                    }
                    // close the session
                    Try.Op(wrapper.Session.Close);
                    Try.Op(wrapper.Session.Dispose);
                    wrapper.Session = null;
                }
            }
            catch (Exception ex) {
                _logger.Error(ex, "Failed to remove session '{id}'", id);
            }
        }
Exemplo n.º 5
0
        /// <inheritdoc/>
        public async Task RemoveSessionAsync(ConnectionModel connection, bool onlyIfEmpty = true)
        {
            var key = new ConnectionIdentifier(connection);
            await _lock.WaitAsync();

            try {
                if (!_sessions.TryGetValue(key, out var wrapper) || wrapper?.Session == null)
                {
                    return;
                }
                var session = wrapper.Session;
                if (onlyIfEmpty && session.SubscriptionCount > 0)
                {
                    return;
                }
                // Remove subscriptions
                if (session.SubscriptionCount > 0)
                {
                    if (onlyIfEmpty)
                    {
                        return;
                    }
                    Try.Op(() => session.RemoveSubscriptions(session.Subscriptions));
                }
                _sessions.Remove(key);
                Try.Op(session.Close);
                Try.Op(session.Dispose);
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 6
0
        /// <inheritdoc/>
        public Task <T> ExecuteServiceAsync <T>(ConnectionModel connection,
                                                CredentialModel elevation, int priority, Func <Session, Task <T> > service,
                                                TimeSpan?timeout, CancellationToken ct, Func <Exception, bool> handler)
        {
            if (connection.Endpoint == null)
            {
                throw new ArgumentNullException(nameof(connection));
            }
            if (string.IsNullOrEmpty(connection.Endpoint?.Url))
            {
                throw new ArgumentNullException(nameof(connection.Endpoint.Url));
            }
            var key = new ConnectionIdentifier(connection);

            while (!_cts.IsCancellationRequested)
            {
                var client = GetOrCreateSession(key);
                if (!client.Inactive)
                {
                    var scheduled = client.TryScheduleServiceCall(elevation, priority,
                                                                  service, handler, timeout, ct, out var result);
                    if (scheduled)
                    {
                        // Session is owning the task to completion now.
                        return(result);
                    }
                }
                // Create new session next go around
                EvictIfInactive(key);
            }
            return(Task.FromCanceled <T>(_cts.Token));
        }
            /// <summary>
            /// Run export cycles
            /// </summary>
            /// <param name="id"></param>
            /// <param name="diagnostics"></param>
            /// <param name="ct"></param>
            /// <returns></returns>
            private async Task UploadModelAsync(ConnectionIdentifier id, DiagnosticsModel diagnostics,
                                                CancellationToken ct)
            {
                var fullPath = Path.Combine(Path.GetTempPath(), FileName);

                try {
                    _outer._logger.Information("Start model upload to {fileName} for {url}.",
                                               FileName, id.Connection.Endpoint.Url);
                    using (var file = new FileStream(fullPath, FileMode.Create))
                        using (var stream = new GZipStream(file, CompressionMode.Compress)) {
                            // TODO: Try read nodeset from namespace metadata!
                            // ...

                            // Otherwise browse model
                            await BrowseEncodeModelAsync(id.Connection.Endpoint, diagnostics, stream, ct);
                        }
                    // now upload file
                    await _outer._upload.SendFileAsync(fullPath, Encoding);

                    _outer._logger.Information("Model uploaded to {fileName} for {url}.",
                                               FileName, id.Connection.Endpoint.Url);
                }
                catch (OperationCanceledException) {
                    _outer._logger.Information("Cancelled model upload of {fileName} for {url}",
                                               FileName, id.Connection.Endpoint.Url);
                }
                catch (Exception ex) {
                    _outer._logger.Error(ex, "Error during exportto {fileName} for {url}.",
                                         FileName, id.Connection.Endpoint.Url);
                }
                finally {
                    File.Delete(fullPath);
                    _outer._tasks.TryRemove(id, out var tmp);
                }
            }
 /// <summary>
 /// Create model upload task
 /// </summary>
 /// <param name="outer"></param>
 /// <param name="id"></param>
 /// <param name="contentType"></param>
 /// <param name="diagnostics"></param>
 public ModelUploadTask(DataUploadServices outer, ConnectionIdentifier id,
                        string contentType, DiagnosticsModel diagnostics)
 {
     Encoding  = ValidateEncoding(contentType, out var extension);
     StartTime = DateTime.UtcNow;
     FileName  = $"{id.GetHashCode()}_{StartTime.ToBinary()}{extension}";
     _outer    = outer;
     _cts      = new CancellationTokenSource();
     _job      = _outer._scheduler.Run(() => UploadModelAsync(id, diagnostics, _cts.Token));
 }
Exemplo n.º 9
0
        /// <inheritdoc/>
        public async Task <Session> GetOrCreateSessionAsync(ConnectionModel connection,
                                                            bool createIfNotExists)
        {
            // Find session and if not exists create
            var id = new ConnectionIdentifier(connection);
            await _lock.WaitAsync();

            try {
                if (!_sessions.TryGetValue(id, out var wrapper) && createIfNotExists)
                {
                    var sessionName = id.ToString();
                    var applicationConfiguration = _clientConfig.ToApplicationConfiguration(true);
                    var endpointConfiguration    = _clientConfig.ToEndpointConfiguration();
                    var endpointDescription      = new EndpointDescription(id.Connection.Endpoint.Url);
                    var configuredEndpoint       = new ConfiguredEndpoint(
                        null, endpointDescription, endpointConfiguration);

                    _logger.Information("Trying to create session {sessionName}...",
                                        sessionName);
                    using (new PerfMarker(_logger, sessionName)) {
                        var userIdentity = connection.User.ToStackModel() ??
                                           new UserIdentity(new AnonymousIdentityToken());
                        var session = await Session.Create(
                            applicationConfiguration, configuredEndpoint,
                            true, sessionName, _clientConfig.DefaultSessionTimeout,
                            userIdentity, null);

                        _logger.Information($"Session '{sessionName}' created.");

                        _logger.Information("Loading Complex Type System....");

                        var complexTypeSystem = new ComplexTypeSystem(session);
                        await complexTypeSystem.Load();

                        _logger.Information("Complex Type system loaded.");

                        if (_clientConfig.KeepAliveInterval > 0)
                        {
                            session.KeepAliveInterval = _clientConfig.KeepAliveInterval;
                            session.KeepAlive        += Session_KeepAlive;
                        }
                        wrapper = new SessionWrapper {
                            MissedKeepAlives = 0,
                            MaxKeepAlives    = _clientConfig.MaxKeepAliveCount,
                            Session          = session
                        };
                        _sessions.Add(id, wrapper);
                    }
                }
                return(wrapper?.Session);
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 10
0
        /// <inheritdoc/>
        public Session GetOrCreateSession(ConnectionModel connection,
                                          bool createIfNotExists)
        {
            // Find session and if not exists create
            var id = new ConnectionIdentifier(connection);

            _lock.Wait();
            try {
                // try to get an existing session
                if (!_sessions.TryGetValue(id, out var wrapper))
                {
                    if (!createIfNotExists)
                    {
                        return(null);
                    }
                    wrapper = new SessionWrapper()
                    {
                        Id = id.ToString(),
                        MissedKeepAlives = 0,
                        // TODO this seem not to be the appropriate configuration argument
                        MaxKeepAlives  = (int)_clientConfig.MaxKeepAliveCount,
                        State          = SessionState.Init,
                        Session        = null,
                        ReportedStatus = StatusCodes.Good,
                        IdleCount      = 0
                    };
                    _sessions.AddOrUpdate(id, wrapper);
                    TriggerKeepAlive();
                }
                switch (wrapper.State)
                {
                case SessionState.Running:
                case SessionState.Refresh:
                    return(wrapper.Session);

                case SessionState.Retry:
                case SessionState.Init:
                case SessionState.Failed:
                case SessionState.Disconnect:
                    break;

                default:
                    throw new InvalidOperationException($"Illegal SessionState ({wrapper.State})");
                }
            }
            catch (Exception ex) {
                _logger.Error(ex, "Failed to get/create session for Id '{id}'", id);
            }
            finally {
                _lock.Release();
            }
            return(null);
        }
Exemplo n.º 11
0
        /// <inheritdoc/>
        public int GetNumberOfConnectionRetries(ConnectionModel connection)
        {
            var key = new ConnectionIdentifier(connection);

            _lock.Wait();
            try {
                if (!_sessions.TryGetValue(key, out var wrapper))
                {
                    return(0);
                }
                return(wrapper.NumberOfConnectRetries);
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 12
0
        /// <inheritdoc/>
        public bool IsConnectionOk(ConnectionModel connection)
        {
            var key = new ConnectionIdentifier(connection);

            _lock.Wait();
            try {
                if (!_sessions.TryGetValue(key, out var wrapper))
                {
                    return(false);
                }
                return(wrapper.State == SessionState.Running);
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 13
0
        /// <inheritdoc/>
        public async Task <Session> GetOrCreateSessionAsync(ConnectionModel connection,
                                                            bool createIfNotExists)
        {
            // Find session and if not exists create
            var id = new ConnectionIdentifier(connection);
            await _lock.WaitAsync();

            try {
                if (!_sessions.TryGetValue(id, out var wrapper) && createIfNotExists)
                {
                    var endpointUrlCandidates = id.Connection.Endpoint.Url.YieldReturn();
                    if (id.Connection.Endpoint.AlternativeUrls != null)
                    {
                        endpointUrlCandidates = endpointUrlCandidates.Concat(
                            id.Connection.Endpoint.AlternativeUrls);
                    }
                    var exceptions = new List <Exception>();
                    foreach (var endpointUrl in endpointUrlCandidates)
                    {
                        try {
                            wrapper = await CreateSessionAsync(endpointUrl, id);

                            if (wrapper?.Session != null)
                            {
                                _logger.Information("Connected on {endpointUrl}", endpointUrl);
                                _sessions.Add(id, wrapper);
                                return(wrapper?.Session);
                            }
                        }
                        catch (Exception ex) {
                            _logger.Debug("Failed to connect on {endpointUrl}: {message} - try again...",
                                          endpointUrl, ex.Message);
                            exceptions.Add(ex);
                        }
                    }
                    throw new AggregateException(exceptions);
                }
                return(wrapper?.Session);
            }
            catch (Exception ex) {
                _logger.Error(ex, "Failed to get or create session.");
                return(null);
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 14
0
 /// <summary>
 /// Create handle
 /// </summary>
 /// <param name="outer"></param>
 /// <param name="connection"></param>
 /// <param name="callback"></param>
 public CallbackHandle(ClientServices outer, ConnectionModel connection,
                       Func <EndpointConnectivityState, Task> callback)
 {
     Callback    = callback;
     _outer      = outer;
     _connection = new ConnectionIdentifier(connection);
     _outer._callbacks.AddOrUpdate(_connection,
                                   new HashSet <CallbackHandle> {
         this
     },
                                   (id, list) => {
         lock (list) {
             list.Add(this);
             return(list);
         }
     });
 }
        public PerConnectionMonitor(string connection)
        {
            Connection = new ConnectionIdentifier(connection);
            _keepAliveHandler.OnPingSample += KeepAliveHandlerOnOnPingSample;
            _ipcHandler.OnPingSample       += IpcHandlerOnOnPingSample;

            _keepAliveHandler.OnClientRecv += _pingOpCodeDetector.ClientRecv;
            _keepAliveHandler.OnClientSent += _pingOpCodeDetector.ClientSent;
            _ipcHandler.OnClientRecv       += _pingOpCodeDetector.ClientRecv;
            _ipcHandler.OnClientSent       += _pingOpCodeDetector.ClientSent;

            _pingOpCodeDetector.OnPingOpCodeDetected += opCode =>
            {
                _ipcHandler.PingOpCode = opCode;
                OnPingOpCodeDetected?.Invoke(opCode);
            };
        }
Exemplo n.º 16
0
 /// <summary>
 /// Handle inactive
 /// </summary>
 /// <param name="id"></param>
 /// <returns></returns>
 private void EvictIfInactive(ConnectionIdentifier id)
 {
     _lock.Wait();
     try {
         if (_clients.TryGetValue(id, out var item))
         {
             if (item.Inactive && _clients.Remove(id))
             {
                 item.Dispose();
                 _logger.Debug("Evicted inactive session from session cache.");
             }
         }
     }
     finally {
         _lock.Release();
     }
 }
Exemplo n.º 17
0
        /// <summary>
        /// Notify about session/endpoint state changes
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        private Task NotifyStateChangeAsync(ConnectionModel connection,
                                            EndpointConnectivityState state)
        {
            var id = new ConnectionIdentifier(connection);

            if (_callbacks.TryGetValue(id, out var list))
            {
                lock (list) {
                    if (list.Count > 0)
                    {
                        return(Task.WhenAll(list.Select(cb => cb.Callback.Invoke(state)))
                               .ContinueWith(_ => Task.CompletedTask));
                    }
                }
            }
            return(Task.CompletedTask);
        }
Exemplo n.º 18
0
 /// <summary>
 /// Create session
 /// </summary>
 /// <param name="id"></param>
 /// <returns></returns>
 private IClientSession GetOrCreateSession(ConnectionIdentifier id)
 {
     _lock.Wait();
     try {
         if (!_clients.TryGetValue(id, out var session))
         {
             session = ClientSession.Create(
                 _appConfig, id.Connection, _logger,
                 NotifyStateChangeAsync, _maxOpTimeout);
             _clients.Add(id, session);
             _logger.Debug("Add new session to session cache.");
         }
         return(session);
     }
     finally {
         _lock.Release();
     }
 }
Exemplo n.º 19
0
        /// <inheritdoc/>
        public async Task RemoveSessionAsync(ConnectionModel connection, bool onlyIfEmpty = true)
        {
            var     key     = new ConnectionIdentifier(connection);
            Session session = null;
            await _lock.WaitAsync();

            try {
                if (!_sessions.TryGetValue(key, out var wrapper))
                {
                    return;
                }

                session = wrapper.Session;
                if (onlyIfEmpty && session != null && session.SubscriptionCount > 0)
                {
                    return;
                }
                _sessions.Remove(key);
            }
            finally {
                _lock.Release();
            }
            try {
                if (session != null)
                {
                    // Remove subscriptions
                    if (session.SubscriptionCount > 0)
                    {
                        foreach (var subscription in session.Subscriptions)
                        {
                            Try.Op(() => subscription.DeleteItems());
                        }
                        Try.Op(() => session.RemoveSubscriptions(session.Subscriptions));
                    }
                    Try.Op(session.Close);
                    Try.Op(session.Dispose);
                }
            }
            catch (Exception ex) {
                _logger.Error(ex, "Session '{name}' removal failure.", connection);
            }
        }
Exemplo n.º 20
0
        /// <inheritdoc/>
        public async Task RemoveSessionAsync(ConnectionModel connection, bool onlyIfEmpty = true)
        {
            var key = new ConnectionIdentifier(connection);
            await _lock.WaitAsync().ConfigureAwait(false);

            try {
                if (!_sessions.TryGetValue(key, out var wrapper))
                {
                    return;
                }
                if (onlyIfEmpty && wrapper._subscriptions.Count == 0)
                {
                    wrapper.State = SessionState.Disconnect;
                    TriggerKeepAlive();
                }
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 21
0
        /// <inheritdoc/>
        public void UnregisterSubscription(ISubscription subscription)
        {
            var id = new ConnectionIdentifier(subscription.Connection);

            _lock.Wait();
            try {
                if (!_sessions.TryGetValue(id, out var wrapper))
                {
                    return;
                }
                if (wrapper._subscriptions.TryRemove(subscription.Id, out _))
                {
                    _logger.Information("Subscription '{subscriptionId}' unregistered from session '{sessionId}' in state {state}",
                                        subscription.Id, id, wrapper.State);
                }
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 22
0
 /// <summary>
 /// Handles the refresh state of a session
 /// </summary>
 /// <param name="id"></param>
 /// <param name="wrapper"></param>
 /// <param name="ct"></param>
 /// <returns></returns>
 private async Task HandleRefreshAsync(ConnectionIdentifier id,
                                       SessionWrapper wrapper, CancellationToken ct)
 {
     try {
         _logger.Debug("Refreshing session '{id}'", id);
         if (wrapper.Session != null)
         {
             if (StatusCode.IsGood(wrapper.ReportedStatus))
             {
                 if (wrapper.Session.Connected &&
                     !wrapper.Session.KeepAliveStopped)
                 {
                     // Fetch namespaces in case, there was some new Uris added to the server
                     wrapper.Session.FetchNamespaceTables();
                     foreach (var subscription in wrapper._subscriptions.Values)
                     {
                         if (!ct.IsCancellationRequested)
                         {
                             await subscription.ActivateAsync(wrapper.Session).ConfigureAwait(false);
                         }
                     }
                     _logger.Debug("Refreshing done for session '{id}'", id);
                     wrapper.State = SessionState.Running;
                     return;
                 }
                 wrapper.ReportedStatus = StatusCodes.BadNoCommunication;
             }
             wrapper.State = SessionState.Retry;
             await HandleRetryAsync(id, wrapper, ct).ConfigureAwait(false);
         }
         else
         {
             wrapper.State = SessionState.Failed;
             await HandleInitAsync(id, wrapper, ct).ConfigureAwait(false);
         }
     }
     catch (Exception e) {
         _logger.Error(e, "Failed to refresh session '{id}'", id);
     }
 }
Exemplo n.º 23
0
        /// <summary>
        /// Handle retry state of a session
        /// </summary>
        /// <param name="id"></param>
        /// <param name="wrapper"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private async Task HandleRetryAsync(ConnectionIdentifier id,
                                            SessionWrapper wrapper, CancellationToken ct)
        {
            try {
                if (!wrapper._subscriptions.Any())
                {
                    if (wrapper.IdleCount < wrapper.MaxKeepAlives)
                    {
                        wrapper.IdleCount++;
                    }
                    else
                    {
                        _logger.Information("Session '{id}' set to disconnect in {state}", id, wrapper.State);
                        wrapper.State = SessionState.Disconnect;
                        await HandleDisconnectAsync(id, wrapper).ConfigureAwait(false);

                        return;
                    }
                }
                else
                {
                    wrapper.IdleCount = 0;
                }

                wrapper.MissedKeepAlives++;
                _logger.Information("Session '{id}' missed {keepAlives} Keepalive(s) due to {status}, " +
                                    "waiting to reconnect...", id, wrapper.MissedKeepAlives, wrapper.ReportedStatus);
                if (!ct.IsCancellationRequested)
                {
                    wrapper.Session.Reconnect();
                    wrapper.ReportedStatus   = StatusCodes.Good;
                    wrapper.State            = SessionState.Running;
                    wrapper.MissedKeepAlives = 0;

                    // reactivate all subscriptions
                    foreach (var subscription in wrapper._subscriptions.Values)
                    {
                        if (!ct.IsCancellationRequested)
                        {
                            await subscription.ActivateAsync(wrapper.Session).ConfigureAwait(false);
                        }
                    }
                }
                return;
            }
            catch (Exception e) {
                wrapper.NumberOfConnectRetries++;
                if (e is ServiceResultException sre)
                {
                    switch (sre.StatusCode)
                    {
                    case StatusCodes.BadNotConnected:
                    case StatusCodes.BadNoCommunication:
                    case StatusCodes.BadSessionNotActivated:
                    case StatusCodes.BadServerHalted:
                    case StatusCodes.BadServerNotConnected:
                        _logger.Warning("Failed to reconnect session '{id}', " +
                                        "will retry later", id);
                        if (wrapper.MissedKeepAlives < wrapper.MaxKeepAlives)
                        {
                            // retry later
                            return;
                        }
                        break;

                    default:
                        break;
                    }
                }
                _logger.Warning("Failed to reconnect session '{id}' due to {exception}, " +
                                " disposing and trying to create new", id, e.Message);
            }

            // cleanup the session
            if (wrapper.Session.SubscriptionCount > 0)
            {
                foreach (var subscription in wrapper.Session.Subscriptions)
                {
                    Try.Op(() => subscription.DeleteItems());
                    Try.Op(() => subscription.Delete(true));
                }
                Try.Op(() => wrapper.Session.RemoveSubscriptions(wrapper.Session.Subscriptions));
            }
            Try.Op(wrapper.Session.Close);
            Try.Op(wrapper.Session.Dispose);
            wrapper.Session          = null;
            wrapper.MissedKeepAlives = 0;
            wrapper.ReportedStatus   = StatusCodes.Good;
            wrapper.State            = SessionState.Failed;

            await HandleInitAsync(id, wrapper, ct).ConfigureAwait(false);
        }
Exemplo n.º 24
0
        /// <inheritdoc/>
        public async Task <Session> GetOrCreateSessionAsync(ConnectionModel connection,
                                                            bool createIfNotExists)
        {
            // Find session and if not exists create
            var id = new ConnectionIdentifier(connection);
            await _lock.WaitAsync();

            try {
                if (!_sessions.TryGetValue(id, out var wrapper) && createIfNotExists)
                {
                    var sessionName = id.ToString();
                    var applicationConfiguration = _clientConfig.ToApplicationConfiguration(true);
                    var endpointConfiguration    = _clientConfig.ToEndpointConfiguration();
                    var endpointDescription      = SelectEndpoint(id.Connection.Endpoint.Url, id.Connection.Endpoint.SecurityMode, id.Connection.Endpoint.SecurityPolicy, (int)(connection.Endpoint.OperationTimeout.HasValue ? connection.Endpoint.OperationTimeout.Value.TotalMilliseconds : defaultOperationTimeout));

                    if (endpointDescription == null)
                    {
                        throw new EndpointNotAvailableException(id.Connection.Endpoint.Url, id.Connection.Endpoint.SecurityMode, id.Connection.Endpoint.SecurityPolicy);
                    }

                    if (id.Connection.Endpoint.SecurityMode.HasValue && id.Connection.Endpoint.SecurityMode != SecurityMode.None && endpointDescription.SecurityMode == MessageSecurityMode.None)
                    {
                        _logger.Warning("Although the use of security was configured, there was no security-enabled endpoint available at url {endpointUrl}. An endpoint with no security will be used.", id.Connection.Endpoint.Url);
                    }

                    var configuredEndpoint = new ConfiguredEndpoint(
                        null, endpointDescription, endpointConfiguration);

                    _logger.Information("Trying to create session {sessionName}...",
                                        sessionName);
                    using (new PerfMarker(_logger, sessionName)) {
                        var userIdentity = connection.User.ToStackModel() ??
                                           new UserIdentity(new AnonymousIdentityToken());
                        var session = await Session.Create(
                            applicationConfiguration, configuredEndpoint,
                            true, sessionName, _clientConfig.DefaultSessionTimeout,
                            userIdentity, null);

                        _logger.Information($"Session '{sessionName}' created.");

                        _logger.Information("Loading Complex Type System....");

                        try {
                            var complexTypeSystem = new ComplexTypeSystem(session);
                            await complexTypeSystem.Load();

                            _logger.Information("Complex Type system loaded.");
                        }
                        catch (Exception ex) {
                            _logger.Error(ex, "Failed to load Complex Type System");
                        }

                        if (_clientConfig.KeepAliveInterval > 0)
                        {
                            session.KeepAliveInterval = _clientConfig.KeepAliveInterval;
                            session.KeepAlive        += Session_KeepAlive;
                        }
                        wrapper = new SessionWrapper {
                            MissedKeepAlives = 0,
                            MaxKeepAlives    = _clientConfig.MaxKeepAliveCount,
                            Session          = session
                        };
                        _sessions.Add(id, wrapper);
                    }
                }
                return(wrapper?.Session);
            }
            finally {
                _lock.Release();
            }
        }
Exemplo n.º 25
0
 public ConnectionContext(Win32PInvoke_iphlpapi.MIB_TCPROW_OWNER_PID connection)
 {
     Connection   = connection;
     ConnectionID = new ConnectionIdentifier(Connection.LocalAddress + ":" + Connection.LocalPort + "=>" +
                                             Connection.RemoteAddress + ":" + Connection.RemotePort);
 }
Exemplo n.º 26
0
        /// <summary>
        /// Create session against endpoint
        /// </summary>
        /// <param name="endpointUrl"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        private async Task <Session> CreateSessionAsync(string endpointUrl, ConnectionIdentifier id)
        {
            var sessionName = $"Azure IIoT Publisher - {id}";

            // Validate certificates
            void OnValidate(CertificateValidator sender, CertificateValidationEventArgs e)
            {
                if (!e.Accept && e.Error.StatusCode == StatusCodes.BadCertificateUntrusted)
                {
                    // Validate thumbprint provided
                    if (e.Certificate.RawData != null &&
                        id.Connection.Endpoint.Certificate != null &&
                        e.Certificate.Thumbprint == id.Connection.Endpoint.Certificate)
                    {
                        // Validate
                        e.Accept = true;
                    }
                    else if (_clientConfig.AutoAcceptUntrustedCertificates)
                    {
                        _logger.Warning("Publisher is configured to accept untrusted certs.  " +
                                        "Accepting untrusted certificate on endpoint {endpointUrl}",
                                        endpointUrl);
                        e.Accept = true;
                    }
                }
            };

            var applicationConfiguration = await _clientConfig.
                                           ToApplicationConfigurationAsync(_identity, true, OnValidate);

            var endpointConfiguration = _clientConfig.ToEndpointConfiguration();

            var endpointDescription = SelectEndpoint(endpointUrl,
                                                     id.Connection.Endpoint.SecurityMode, id.Connection.Endpoint.SecurityPolicy,
                                                     (int)(id.Connection.OperationTimeout.HasValue ?
                                                           id.Connection.OperationTimeout.Value.TotalMilliseconds :
                                                           kDefaultOperationTimeout));

            if (endpointDescription == null)
            {
                throw new EndpointNotAvailableException(endpointUrl,
                                                        id.Connection.Endpoint.SecurityMode, id.Connection.Endpoint.SecurityPolicy);
            }

            if (id.Connection.Endpoint.SecurityMode.HasValue &&
                id.Connection.Endpoint.SecurityMode != SecurityMode.None &&
                endpointDescription.SecurityMode == MessageSecurityMode.None)
            {
                _logger.Warning("Although the use of security was configured, " +
                                "there was no security-enabled endpoint available at url " +
                                "{endpointUrl}. An endpoint with no security will be used.",
                                endpointUrl);
            }

            var configuredEndpoint = new ConfiguredEndpoint(
                null, endpointDescription, endpointConfiguration);

            _logger.Information("Trying to create session {sessionName}...",
                                sessionName);
            using (new PerfMarker(_logger, sessionName)) {
                var userIdentity = id.Connection.User.ToStackModel() ??
                                   new UserIdentity(new AnonymousIdentityToken());
                var session = await Session.Create(
                    applicationConfiguration, configuredEndpoint,
                    true, sessionName, _clientConfig.DefaultSessionTimeout,
                    userIdentity, null);

                if (sessionName != session.SessionName)
                {
                    _logger.Warning("Session '{sessionName}' created with a revised name '{name}'",
                                    sessionName, session.SessionName);
                }
                _logger.Information("Session '{sessionName}' created.", sessionName);

                _logger.Information("Loading Complex Type System....");
                try {
                    var complexTypeSystem = new ComplexTypeSystem(session);
                    await complexTypeSystem.Load();

                    _logger.Information("Complex Type system loaded.");
                }
                catch (Exception ex) {
                    _logger.Error(ex, "Failed to load Complex Type System");
                }

                // TODO - what happens when KeepAliveInterval is 0???
                if (_clientConfig.KeepAliveInterval > 0)
                {
                    session.KeepAliveInterval = _clientConfig.KeepAliveInterval;
                    session.KeepAlive        += Session_KeepAlive;
                    session.Notification     += Session_Notification;
                }
                return(session);
            }
        }
Exemplo n.º 27
0
        /// <summary>
        /// Create session against endpoint
        /// </summary>
        /// <param name="endpointUrl"></param>
        /// <param name="id"></param>
        /// <param name="wrapper"></param>
        /// <returns></returns>
        private async Task <Session> CreateSessionAsync(string endpointUrl, ConnectionIdentifier id,
                                                        SessionWrapper wrapper)
        {
            var sessionName = $"Azure IIoT {id}";

            var endpointDescription = SelectEndpoint(endpointUrl,
                                                     id.Connection.Endpoint.SecurityMode, id.Connection.Endpoint.SecurityPolicy,
                                                     (int)(id.Connection.OperationTimeout.HasValue ?
                                                           id.Connection.OperationTimeout.Value.TotalMilliseconds :
                                                           kDefaultOperationTimeout));

            if (endpointDescription == null)
            {
                throw new EndpointNotAvailableException(endpointUrl,
                                                        id.Connection.Endpoint.SecurityMode, id.Connection.Endpoint.SecurityPolicy);
            }

            if (id.Connection.Endpoint.SecurityMode.HasValue &&
                id.Connection.Endpoint.SecurityMode != SecurityMode.None &&
                endpointDescription.SecurityMode == MessageSecurityMode.None)
            {
                _logger.Warning("Although the use of security was configured, " +
                                "there was no security-enabled endpoint available at url " +
                                "{endpointUrl}. An endpoint with no security will be used.",
                                endpointUrl);
            }

            var configuredEndpoint = new ConfiguredEndpoint(
                null, endpointDescription, _endpointConfiguration);

            _logger.Information("Creating session '{id}' for endpoint '{endpointUrl}'...", id, endpointUrl);
            using (new PerfMarker(_logger, sessionName)) {
                var userIdentity = id.Connection.User.ToStackModel() ??
                                   new UserIdentity(new AnonymousIdentityToken());
                var session = await Session.Create(
                    _applicationConfiguration, configuredEndpoint,
                    true, sessionName, _clientConfig.DefaultSessionTimeout,
                    userIdentity, null).ConfigureAwait(false);

                session.Handle  = wrapper;
                wrapper.Session = session;

                session.KeepAliveInterval = _clientConfig.KeepAliveInterval > 0 ?
                                            _clientConfig.KeepAliveInterval : kDefaultOperationTimeout;

                session.KeepAlive    += Session_KeepAlive;
                session.Notification += Session_Notification;


                // TODO - store the created session id (node id)?
                if (sessionName != session.SessionName)
                {
                    _logger.Warning("Session '{id}' created with a revised name '{name}'",
                                    id, session.SessionName);
                }
                _logger.Information("Session '{id}' created, loading complex type system ... ", id);
                try {
                    var complexTypeSystem = new ComplexTypeSystem(session);
                    await complexTypeSystem.Load().ConfigureAwait(false);

                    _logger.Information("Session '{id}' complex type system loaded", id);
                }
                catch (Exception ex) {
                    _logger.Error(ex, "Failed to load complex type system for session '{id}'", id);
                }

                return(session);
            }
        }
Exemplo n.º 28
0
        /// <inheritdoc/>
        public async Task <Session> GetOrCreateSessionAsync(ConnectionModel connection,
                                                            bool createIfNotExists, uint statusCode = StatusCodes.Good)
        {
            // Find session and if not exists create
            var            id      = new ConnectionIdentifier(connection);
            SessionWrapper wrapper = null;
            await _lock.WaitAsync();

            try {
                // try to get an existing session
                try {
                    if (!_sessions.TryGetValue(id, out wrapper))
                    {
                        if (!createIfNotExists)
                        {
                            return(null);
                        }
                        wrapper = new SessionWrapper()
                        {
                            MissedKeepAlives = 0,
                            MaxKeepAlives    = _clientConfig.MaxKeepAliveCount,
                            State            = SessionState.Init,
                            Session          = null,
                            IdleCount        = 0
                        };
                        _sessions.Add(id, wrapper);
                    }
                    switch (wrapper.State)
                    {
                    case SessionState.Reconnecting:
                    case SessionState.Connecting:
                        // nothing to do the consumer will either retry or handle the issue
                        return(null);

                    case SessionState.Running:
                        if (StatusCode.IsGood(statusCode))
                        {
                            return(wrapper.Session);
                        }
                        wrapper.State = SessionState.Reconnecting;
                        break;

                    case SessionState.Retry:
                        wrapper.State = SessionState.Reconnecting;
                        break;

                    case SessionState.Init:
                    case SessionState.Failed:
                        wrapper.State = SessionState.Connecting;
                        break;

                    default:
                        throw new InvalidOperationException($"Illegal SessionState ({wrapper.State})");
                    }
                }
                catch (Exception ex) {
                    _logger.Error(ex, "Failed to get/create as session for Id {id}.", id);
                    throw;
                }
                finally {
                    _lock.Release();
                }
                while (true)
                {
                    switch (wrapper.State)
                    {
                    case SessionState.Reconnecting:
                        // attempt to reactivate
                        try {
                            wrapper.MissedKeepAlives++;
                            _logger.Information("Session '{name}' missed {keepAlives} keep alive(s) due to {status}." +
                                                " Awaiting for reconnect...", wrapper.Session.SessionName,
                                                wrapper.MissedKeepAlives, new StatusCode(statusCode));
                            wrapper.Session.Reconnect();
                            wrapper.State            = SessionState.Running;
                            wrapper.MissedKeepAlives = 0;
                            return(wrapper.Session);
                        }
                        catch (Exception e) {
                            if (e is ServiceResultException sre)
                            {
                                switch (sre.StatusCode)
                                {
                                case StatusCodes.BadNotConnected:
                                case StatusCodes.BadNoCommunication:
                                case StatusCodes.BadSessionNotActivated:
                                case StatusCodes.BadServerHalted:
                                case StatusCodes.BadServerNotConnected:
                                    _logger.Warning("Failed to reconnect session {sessionName}." +
                                                    " Retry reconnection later.", wrapper.Session.SessionName);
                                    wrapper.State = SessionState.Retry;
                                    if (wrapper.MissedKeepAlives < wrapper.MaxKeepAlives)
                                    {
                                        return(null);
                                    }
                                    break;

                                default:
                                    break;
                                }
                            }
                            // cleanup the session
                            _logger.Warning("Failed to reconnect session {sessionName} due to {exception}." +
                                            " Disposing and trying create new.", wrapper.Session.SessionName, e.Message);
                            if (wrapper.Session.SubscriptionCount > 0)
                            {
                                foreach (var subscription in wrapper.Session.Subscriptions)
                                {
                                    Try.Op(() => subscription.DeleteItems());
                                    Try.Op(() => subscription.Delete(true));
                                }
                                Try.Op(() => wrapper.Session.RemoveSubscriptions(wrapper.Session.Subscriptions));
                            }
                            Try.Op(wrapper.Session.Close);
                            Try.Op(wrapper.Session.Dispose);
                            wrapper.Session          = null;
                            wrapper.MissedKeepAlives = 0;
                            wrapper.State            = SessionState.Connecting;
                        }
                        break;

                    case SessionState.Connecting:
                        if (wrapper.Session != null)
                        {
                            _logger.Warning("Session {sessionName} still attached to wrapper in {state}",
                                            wrapper.Session.SessionName, wrapper.State);
                            Try.Op(wrapper.Session.Dispose);
                            wrapper.Session = null;
                        }
                        var endpointUrlCandidates = id.Connection.Endpoint.Url.YieldReturn();
                        if (id.Connection.Endpoint.AlternativeUrls != null)
                        {
                            endpointUrlCandidates = endpointUrlCandidates.Concat(
                                id.Connection.Endpoint.AlternativeUrls);
                        }
                        var exceptions = new List <Exception>();
                        foreach (var endpointUrl in endpointUrlCandidates)
                        {
                            try {
                                var session = await CreateSessionAsync(endpointUrl, id);

                                if (session != null)
                                {
                                    _logger.Information("Connected on {endpointUrl}", endpointUrl);
                                    wrapper.Session = session;
                                    wrapper.State   = SessionState.Running;
                                    return(wrapper.Session);
                                }
                            }
                            catch (Exception ex) {
                                _logger.Debug("Failed to connect on {endpointUrl}: {message} - try again...",
                                              endpointUrl, ex.Message);
                                exceptions.Add(ex);
                            }
                        }
                        throw new AggregateException(exceptions);

                    default:
                        throw new InvalidOperationException($"Invalid SessionState ({wrapper.State}) not handled.");
                    }
                }
            }
            catch (ServiceResultException sre) {
                _logger.Warning("Failed to get or create session {id} due to {exception}.",
                                id, sre.StatusCode.ToString());
            }
            catch (AggregateException aex) {
                _logger.Warning("Failed to get or create session {id} due to {exception}.",
                                id, aex.Message);
            }
            catch (Exception ex) {
                _logger.Error(ex, "Failed to get or create session.");
            }
            wrapper.State = SessionState.Failed;
            return(null);
        }
Exemplo n.º 29
0
        /// <summary>
        /// Handles the initialization state of the session
        /// </summary>
        /// <param name="id"></param>
        /// <param name="wrapper"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        private async Task HandleInitAsync(ConnectionIdentifier id,
                                           SessionWrapper wrapper, CancellationToken ct)
        {
            try {
                if (wrapper.Session != null)
                {
                    _logger.Warning("Session '{id}' still attached to wrapper in {state}",
                                    id, wrapper.State);
                    Try.Op(wrapper.Session.Dispose);
                    wrapper.Session = null;
                }
                _logger.Debug("Initializing session '{id}'...", id);
                var endpointUrlCandidates = id.Connection.Endpoint.Url.YieldReturn();
                if (id.Connection.Endpoint.AlternativeUrls != null)
                {
                    endpointUrlCandidates = endpointUrlCandidates.Concat(
                        id.Connection.Endpoint.AlternativeUrls);
                }
                var exceptions = new List <Exception>();
                foreach (var endpointUrl in endpointUrlCandidates)
                {
                    try {
                        if (!ct.IsCancellationRequested)
                        {
                            var session = await CreateSessionAsync(endpointUrl, id, wrapper).ConfigureAwait(false);

                            if (session != null)
                            {
                                _logger.Information("Connected to '{endpointUrl}'", endpointUrl);
                                session.Handle  = wrapper;
                                wrapper.Session = session;
                                foreach (var subscription in wrapper._subscriptions.Values)
                                {
                                    await subscription.EnableAsync(wrapper.Session).ConfigureAwait(false);
                                }
                                foreach (var subscription in wrapper._subscriptions.Values)
                                {
                                    await subscription.ActivateAsync(wrapper.Session).ConfigureAwait(false);
                                }
                                wrapper.State = SessionState.Running;
                                _logger.Debug("Session '{id}' successfully initialized", id);
                                return;
                            }
                        }
                    }
                    catch (Exception ex) {
                        _logger.Debug("Failed to connect to {endpointUrl}: {message} - try again...",
                                      endpointUrl, ex.Message);
                        exceptions.Add(ex);
                    }
                }
                throw new AggregateException(exceptions);
            }
            catch (ServiceResultException sre) {
                _logger.Warning("Failed to create session '{id}' due to {exception}",
                                id, sre.StatusCode.ToString());
            }
            catch (AggregateException aex) {
                _logger.Warning("Failed to create session '{id}' due to {exception}",
                                id, aex.Message);
            }
            catch (Exception ex) {
                _logger.Error(ex, "Failed to create session '{id}'", id);
            }
            wrapper.NumberOfConnectRetries++;
            wrapper.State = SessionState.Failed;
        }