/// <summary> /// Adds a new connection to the list of tracked connections. /// </summary> /// <param name="connection">The connection to be added.</param> public bool AddConnection(ITrackingConnection connection) { var newMetadata = new ConnectionMetadata(connection); ConnectionMetadata oldMetadata = null; bool isNewConnection = true; _connections.AddOrUpdate(connection.ConnectionId, newMetadata, (key, old) => { oldMetadata = old; return newMetadata; }); if (oldMetadata != null) { // Kick out the older connection. This should only happen when // a previous connection attempt fails on the client side (e.g. transport fallback). oldMetadata.Connection.End(); // If we have old metadata this isn't a new connection isNewConnection = false; } // Set the initial connection time newMetadata.Initial = DateTime.UtcNow; // Set the keep alive time newMetadata.UpdateKeepAlive(_configurationManager.KeepAlive); return isNewConnection; }
/// <summary> /// Adds a new connection to the list of tracked connections. /// </summary> /// <param name="connection">The connection to be added.</param> public ITrackingConnection AddOrUpdateConnection(ITrackingConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } var newMetadata = new ConnectionMetadata(connection); bool isNewConnection = true; ITrackingConnection oldConnection = null; _connections.AddOrUpdate(connection.ConnectionId, newMetadata, (key, old) => { Logger.LogVerbose(String.Format("Connection {0} exists. Closing previous connection.", old.Connection.ConnectionId)); // Kick out the older connection. This should only happen when // a previous connection attempt fails on the client side (e.g. transport fallback). old.Connection.ApplyState(TransportConnectionStates.Replaced); // Don't bother disposing the registration here since the token source // gets disposed after the request has ended old.Connection.End(); // If we have old metadata this isn't a new connection isNewConnection = false; oldConnection = old.Connection; return newMetadata; }); if (isNewConnection) { Logger.LogInformation(String.Format("Connection {0} is New.", connection.ConnectionId)); connection.IncrementConnectionsCount(); } lock (_counterLock) { _counters.ConnectionsCurrent.RawValue = _connections.Count; } // Set the initial connection time newMetadata.Initial = DateTime.UtcNow; newMetadata.Connection.ApplyState(TransportConnectionStates.Added); return oldConnection; }
/// <summary> /// Adds a new connection to the list of tracked connections. /// </summary> /// <param name="connection">The connection to be added.</param> public bool AddConnection(ITrackingConnection connection) { var newMetadata = new ConnectionMetadata(connection); ConnectionMetadata oldMetadata = null; bool isNewConnection = true; _connections.AddOrUpdate(connection.ConnectionId, newMetadata, (key, old) => { oldMetadata = old; return newMetadata; }); if (oldMetadata != null) { Trace.TraceInformation("Connection exists. Closing previous connection. Old=({0}, {1}) New=({2})", oldMetadata.Connection.IsAlive, oldMetadata.Connection.Url, connection.Url); // Kick out the older connection. This should only happen when // a previous connection attempt fails on the client side (e.g. transport fallback). oldMetadata.Connection.End(); // If we have old metadata this isn't a new connection isNewConnection = false; } else { Trace.TraceInformation("Connection is New=({0}).", connection.Url); } lock (_counterLock) { _counters.ConnectionsCurrent.RawValue = _connections.Count; } // Set the initial connection time newMetadata.Initial = DateTime.UtcNow; // Set the keep alive time newMetadata.UpdateKeepAlive(_configurationManager.KeepAlive); return isNewConnection; }
private void CheckDisconnect(ConnectionMetadata metadata) { try { if (RaiseDisconnect(metadata)) { // Remove the connection from the list RemoveConnection(metadata.Connection); // Fire disconnect on the connection metadata.Connection.Disconnect(); // End the connection metadata.Connection.End(); } } catch (Exception ex) { // Swallow exceptions that might happen during disconnect Trace.TraceInformation("Raising Disconnect failed: {0}", ex); } }
private bool RaiseTimeout(ConnectionMetadata metadata) { // The connection already timed out so do nothing if (metadata.Connection.IsTimedOut) { return(false); } var keepAlive = _configurationManager.KeepAlive; // If keep alive is configured and the connection supports keep alive // don't ever time out if (keepAlive != null && metadata.Connection.SupportsKeepAlive) { return(false); } TimeSpan elapsed = DateTime.UtcNow - metadata.Initial; // Only raise timeout if we're past the configured connection timeout. return(elapsed >= _configurationManager.ConnectionTimeout); }
private bool RaiseTimeout(ConnectionMetadata metadata) { // The connection already timed out so do nothing if (metadata.Connection.IsTimedOut) { return(false); } // If keep alives are enabled and the transport doesn't require timeouts, // i.e. anything but long-polling, don't ever timeout. var keepAlive = _transportOptions.KeepAlive; if (keepAlive != null && !metadata.Connection.RequiresTimeout) { return(false); } TimeSpan elapsed = DateTime.UtcNow - metadata.Initial; // Only raise timeout if we're past the configured connection timeout. return(elapsed >= _transportOptions.LongPolling.PollTimeout); }
async Task <Try <ICloudConnection> > TryCreateCloudConnectionFromServiceIdentity(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler, bool refreshOutOfDateCache, CloudListener cloudListener, string authChain) { Events.CreatingCloudConnectionOnBehalfOf(identity); ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(identity.Id); string productInfo = connectionMetadata.EdgeProductInfo; Option <string> modelId = connectionMetadata.ModelId; ITransportSettings[] transportSettings = GetTransportSettings( this.upstreamProtocol, this.connectionPoolSize, this.proxy, this.useServerHeartbeat, authChain); try { ICloudConnection cc = await CloudConnection.Create( identity, connectionStatusChangedHandler, transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(identity); return(Try.Success(cc)); } catch (UnauthorizedException ex) when(this.trackDeviceState) { return(await this.TryRecoverCloudConnection(identity, connectionStatusChangedHandler, refreshOutOfDateCache, ex)); } }
private void CheckTimeoutAndKeepAlive(ConnectionMetadata metadata) { if (RaiseTimeout(metadata)) { RemoveConnection(metadata.Connection); // If we're past the expiration time then just timeout the connection metadata.Connection.Timeout(); // End the connection metadata.Connection.End(); } else { // The connection is still alive so we need to keep it alive with a server side "ping". // This is for scenarios where networking hardware (proxies, loadbalancers) get in the way // of us handling timeout's or disconnects gracefully if (RaiseKeepAlive(metadata)) { Trace.TraceInformation("KeepAlive(" + metadata.Connection.ConnectionId + ")"); // If the keep alive send fails then kill the connection metadata.Connection.KeepAlive() .Catch(ex => { Trace.TraceInformation("Failed to send keep alive: " + ex.GetBaseException()); RemoveConnection(metadata.Connection); metadata.Connection.End(); }); metadata.UpdateKeepAlive(_configurationManager.KeepAlive); } MarkConnection(metadata.Connection); } }
/// <summary> /// Adds a new connection to the list of tracked connections. /// </summary> /// <param name="connection">The connection to be added.</param> public bool AddConnection(ITrackingConnection connection) { _trace.Source.TraceInformation("TransportHeartBeat: Adding connection {0}", connection.ConnectionId); var newMetadata = new ConnectionMetadata(connection); ConnectionMetadata oldMetadata = null; bool isNewConnection = true; _connections.AddOrUpdate(connection.ConnectionId, newMetadata, (key, old) => { oldMetadata = old; return newMetadata; }); if (oldMetadata != null) { _trace.Source.TraceInformation("TransportHeartBeat: Connection {0} already exists and alive={1}. Closing previous connection id.", oldMetadata.Connection.ConnectionId, oldMetadata.Connection.IsAlive); // Kick out the older connection. This should only happen when // a previous connection attempt fails on the client side (e.g. transport fallback). oldMetadata.Connection.End(); // If we have old metadata this isn't a new connection isNewConnection = false; } else { _trace.Source.TraceInformation("TransportHeartBeat: Connection {0} is new.", connection.ConnectionId); } // Set the initial connection time newMetadata.Initial = DateTime.UtcNow; // Set the keep alive time newMetadata.UpdateKeepAlive(_configurationManager.KeepAlive); return isNewConnection; }
private void CheckTimeoutAndKeepAlive(ConnectionMetadata metadata) { if (RaiseTimeout(metadata)) { // If we're past the expiration time then just timeout the connection metadata.Connection.Timeout(); RemoveConnection(metadata.Connection); } else { // The connection is still alive so we need to keep it alive with a server side "ping". // This is for scenarios where networing hardware (proxies, loadbalancers) get in the way // of us handling timeout's or disconnects gracefully if (RaiseKeepAlive(metadata)) { metadata.Connection.KeepAlive().Catch(); metadata.UpdateKeepAlive(_configurationManager.KeepAlive); } MarkConnection(metadata.Connection); } }
private void CheckTimeoutAndKeepAlive(ConnectionMetadata metadata) { if (RaiseTimeout(metadata)) { // If we're past the expiration time then just timeout the connection metadata.Connection.Timeout(); } else { // The connection is still alive so we need to keep it alive with a server side "ping". // This is for scenarios where networking hardware (proxies, loadbalancers) get in the way // of us handling timeout's or disconnects gracefully if (RaiseKeepAlive(metadata)) { Trace.TraceEvent(TraceEventType.Verbose, 0, "KeepAlive(" + metadata.Connection.ConnectionId + ")"); // Ensure delegate continues to use the C# Compiler static delegate caching optimization. metadata.Connection.KeepAlive().Catch((ex, state) => OnKeepAliveError(ex, state), state: Trace, traceSource: Trace); } MarkConnection(metadata.Connection); } }
/// <summary> /// Adds a new connection to the list of tracked connections. /// </summary> /// <param name="connection">The connection to be added.</param> public bool AddConnection(ITrackingConnection connection) { var newMetadata = new ConnectionMetadata(connection); ConnectionMetadata oldMetadata = null; bool isNewConnection = true; _connections.AddOrUpdate(connection.ConnectionId, newMetadata, (key, old) => { oldMetadata = old; return(newMetadata); }); if (oldMetadata != null) { Trace.TraceInformation("Connection exists. Closing previous connection. Old=({0}, {1}) New=({2})", oldMetadata.Connection.IsAlive, oldMetadata.Connection.Url, connection.Url); // Kick out the older connection. This should only happen when // a previous connection attempt fails on the client side (e.g. transport fallback). oldMetadata.Connection.End(); // If we have old metadata this isn't a new connection isNewConnection = false; } else { Trace.TraceInformation("Connection is New=({0}).", connection.Url); } // Set the initial connection time newMetadata.Initial = DateTime.UtcNow; // Set the keep alive time newMetadata.UpdateKeepAlive(_configurationManager.KeepAlive); return(isNewConnection); }
private void CheckTimeoutAndKeepAlive(ConnectionMetadata metadata) { if (RaiseTimeout(metadata)) { // If we're past the expiration time then just timeout the connection metadata.Connection.Timeout(); EndConnection(metadata); } else { // The connection is still alive so we need to keep it alive with a server side "ping". // This is for scenarios where networking hardware (proxies, loadbalancers) get in the way // of us handling timeout's or disconnects gracefully if (RaiseKeepAlive(metadata)) { Trace.TraceEvent(TraceEventType.Verbose, 0, "KeepAlive(" + metadata.Connection.ConnectionId + ")"); metadata.Connection.KeepAlive() .Catch(ex => { Trace.TraceEvent(TraceEventType.Error, 0, "Failed to send keep alive: " + ex.GetBaseException()); }); } MarkConnection(metadata.Connection); } }
/// <summary> /// Adds a new connection to the list of tracked connections. /// </summary> /// <param name="connection">The connection to be added.</param> public bool AddConnection(ITrackingConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } var newMetadata = new ConnectionMetadata(connection); ConnectionMetadata oldMetadata = null; bool isNewConnection = true; _connections.AddOrUpdate(connection.ConnectionId, newMetadata, (key, old) => { oldMetadata = old; return newMetadata; }); if (oldMetadata != null) { Trace.TraceInformation("Connection {0} exists. Closing previous connection.", oldMetadata.Connection.ConnectionId); // Kick out the older connection. This should only happen when // a previous connection attempt fails on the client side (e.g. transport fallback). // Don't bother disposing the registration here since the token source // gets disposed after the request has ended EndConnection(oldMetadata, disposeRegistration: false); // If we have old metadata this isn't a new connection isNewConnection = false; } else { Trace.TraceInformation("Connection {0} is New.", connection.ConnectionId); } lock (_counterLock) { _counters.ConnectionsCurrent.RawValue = _connections.Count; } // Set the initial connection time newMetadata.Initial = DateTime.UtcNow; // Register for disconnect cancellation newMetadata.Registration = connection.CancellationToken.SafeRegister(OnConnectionEnded, newMetadata); return isNewConnection; }
private bool RaiseTimeout(ConnectionMetadata metadata) { // The connection already timed out so do nothing if (metadata.Connection.IsTimedOut) { return false; } TimeSpan? keepAlive = _configurationManager.KeepAlive; // If keep alive is configured and the connection supports keep alive // don't ever time out if (keepAlive != null && metadata.Connection.SupportsKeepAlive) { return false; } TimeSpan elapsed = DateTime.UtcNow - metadata.Initial; // Only raise timeout if we're past the configured connection timeout. return elapsed >= _configurationManager.ConnectionTimeout; }
public async Task SmokeTest() { // Arrange string edgeProductInfo = "IoTEdge 1.0.7"; var storeProvider = new StoreProvider(new InMemoryDbStoreProvider()); IEntityStore <string, string> store = storeProvider.GetEntityStore <string, string>("connectionMetadata"); var metadataStore = new MetadataStore(store, edgeProductInfo); var deviceProductInfos = new Dictionary <string, string> { ["d1"] = Guid.NewGuid().ToString(), ["d2"] = Guid.NewGuid().ToString(), ["d3"] = Guid.NewGuid().ToString(), ["d3/m1"] = Guid.NewGuid().ToString(), ["d3/m2"] = Guid.NewGuid().ToString() }; var deviceToModelIds = new Dictionary <string, string> { ["d1"] = "dtmi:example:capabailityModels:MXChip;1", ["d2"] = "dtmi:example2:capabailityModels:MXChip;1", ["d3"] = "dtmi:example3:capabailityModels:MXChip;1", ["d3/m1"] = "dtmi:example4:capabailityModels:MXChip;1", ["d3/m2"] = "dtmi:example5:capabailityModels:MXChip;1" }; // Act foreach (KeyValuePair <string, string> kvp in deviceProductInfos) { await metadataStore.SetProductInfo(kvp.Key, kvp.Value); } foreach (KeyValuePair <string, string> kvp in deviceToModelIds) { await metadataStore.SetModelId(kvp.Key, kvp.Value); } var receivedDeviceInfos = new Dictionary <string, string>(); var receivedEdgeDeviceInfos = new Dictionary <string, string>(); var receivedDeviceModelIds = new Dictionary <string, string>(); foreach (string id in deviceProductInfos.Keys) { ConnectionMetadata connectionMetadata = await metadataStore.GetMetadata(id); string productInfo = connectionMetadata.ProductInfo; string deviceEdgeProductInfo = connectionMetadata.EdgeProductInfo; receivedDeviceInfos.Add(id, productInfo); receivedEdgeDeviceInfos.Add(id, deviceEdgeProductInfo); } foreach (string id in deviceToModelIds.Keys) { ConnectionMetadata connectionMetadata = await metadataStore.GetMetadata(id); Option <string> modelId = connectionMetadata.ModelId; modelId.ForEach(m => receivedDeviceModelIds.Add(id, m)); } // Assert Assert.Equal(deviceProductInfos.Count, receivedDeviceInfos.Count); Assert.Equal(deviceProductInfos.Count, receivedEdgeDeviceInfos.Count); Assert.Equal(deviceToModelIds.Count, receivedDeviceModelIds.Count); foreach (KeyValuePair <string, string> kvp in deviceProductInfos) { Assert.Equal(kvp.Value, receivedDeviceInfos[kvp.Key]); Assert.Equal($"{kvp.Value} {edgeProductInfo}", receivedEdgeDeviceInfos[kvp.Key]); } foreach (KeyValuePair <string, string> kvp in deviceToModelIds) { Assert.Equal(kvp.Value, receivedDeviceModelIds[kvp.Key]); } }
public async Task TestSendMessages() { // Arrange const string Id = "id1"; var identity = Mock.Of <IIdentity>(i => i.Id == Id); var twinMessageConverter = new TwinMessageConverter(); var twinCollectionMessageConverter = new TwinCollectionMessageConverter(); var messageConverterProvider = new MessageConverterProvider( new Dictionary <Type, IMessageConverter>() { { typeof(Message), new DeviceClientMessageConverter() }, { typeof(Shared.Twin), twinMessageConverter }, { typeof(TwinCollection), twinCollectionMessageConverter } }); var edgeHubTokenProvider = new Mock <ITokenProvider>(); var clientWatcher = new ClientWatcher(); var clientProvider = new Mock <IClientProvider>(); clientProvider.Setup(c => c.Create(identity, edgeHubTokenProvider.Object, It.IsAny <ITransportSettings[]>(), Option.None <string>())) .Returns(() => new ThrowingClient(clientWatcher, 3)); var deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>(); deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(Id)) .ReturnsAsync( Option.Some( new ServiceIdentity( Id, "dummy", new List <string>(), new ServiceAuthentication(new SymmetricKeyAuthentication("foo", "bar")), ServiceIdentityStatus.Enabled))); deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == Id))) .ReturnsAsync(Option.Some(Id)); var edgeHubIdentity = Mock.Of <IIdentity>(); ConnectionMetadata connectionMetadata = new ConnectionMetadata("edgeProdInfo"); var metadataStore = new Mock <IMetadataStore>(); metadataStore.Setup(p => p.GetMetadata(Id)) .ReturnsAsync(connectionMetadata); var identityProvider = new Mock <IIdentityProvider>(); identityProvider.Setup(i => i.Create(Id)).Returns(identity); var credentialsCache = new Mock <ICredentialsCache>(); var edgeHub = new Mock <IEdgeHub>(); var connectionProvider = new CloudConnectionProvider( messageConverterProvider, 1, clientProvider.Object, Option.None <UpstreamProtocol>(), edgeHubTokenProvider.Object, deviceScopeIdentitiesCache.Object, credentialsCache.Object, edgeHubIdentity, TimeSpan.FromMinutes(10), false, TimeSpan.FromMinutes(10), false, Option.None <IWebProxy>(), metadataStore.Object, scopeAuthenticationOnly: true, trackDeviceState: true, true); connectionProvider.BindEdgeHub(edgeHub.Object); var deviceConnectivityManager = Mock.Of <IDeviceConnectivityManager>(); var connectionManager = new ConnectionManager(connectionProvider, credentialsCache.Object, identityProvider.Object, deviceConnectivityManager); var messagesToSend = new List <IMessage>(); for (int i = 0; i < 10; i++) { var message = new EdgeMessage.Builder(new byte[i]) .SetSystemProperties( new Dictionary <string, string>() { [SystemProperties.MessageId] = i.ToString() }) .Build(); messagesToSend.Add(message); } // Act Option <ICloudProxy> cloudProxyOption = await connectionManager.GetCloudConnection(Id); // Assert Assert.True(cloudProxyOption.HasValue); ICloudProxy cloudProxy = cloudProxyOption.OrDefault(); Assert.True(cloudProxy.IsActive); // Act await RunSendMessages(cloudProxy, messagesToSend); // Assert Assert.Equal(messagesToSend.Count, clientWatcher.ReceivedMessages.Count()); Assert.Equal(5, clientWatcher.OpenAsyncCount); Assert.True(cloudProxy.IsActive); IEnumerable <string> expectedMessageIds = messagesToSend.Select(m => m.SystemProperties[SystemProperties.MessageId]); IEnumerable <string> receivedMessageIds = clientWatcher.ReceivedMessages.Select(m => m.MessageId); Assert.Equal(expectedMessageIds, receivedMessageIds); }
private bool RaiseTimeout(ConnectionMetadata metadata) { // The connection already timed out so do nothing if (metadata.Connection.IsTimedOut) { return false; } // If keep alives are enabled and the transport doesn't require timeouts, // i.e. anything but long-polling, don't ever timeout. var keepAlive = _configurationManager.KeepAlive; if (keepAlive != null && !metadata.Connection.RequiresTimeout) { return false; } TimeSpan elapsed = DateTime.UtcNow - metadata.Initial; // Only raise timeout if we're past the configured connection timeout. return elapsed >= _configurationManager.ConnectionTimeout; }
private bool RaiseDisconnect(ConnectionMetadata metadata) { // The transport is currently dead but it could just be reconnecting // so we to check it's last active time to see if it's over the disconnect // threshold TimeSpan elapsed = DateTime.UtcNow - metadata.LastMarked; // The threshold for disconnect is the transport threshold + (potential network issues) var threshold = metadata.Connection.DisconnectThreshold + _configurationManager.DisconnectTimeout; return elapsed >= threshold; }
private void CheckDisconnect(ConnectionMetadata metadata) { try { if (RaiseDisconnect(metadata)) { // Remove the connection from the list RemoveConnection(metadata.Connection); // Fire disconnect on the connection metadata.Connection.Disconnect(); } } catch (Exception ex) { // Swallow exceptions that might happen during disconnect _trace.Source.TraceInformation("TransportHeartBeat: Raising Disconnect failed: {0}", ex); } }
public static void RunClient(string hostName = "localhost", int port = 11111) { if (hostName == null) { throw new ArgumentNullException("Error: StandaloneClient.hostName null string"); } if (hostName.Length == 0) { throw new ArgumentNullException("Error: StandaloneClient.hostName empty string"); } if (port <= 0 || port > 65535) { throw new ArgumentOutOfRangeException("Error: StandaloneClient.port must be between 1 and 65535 (inclusive)."); } bool done = false; TcpClient myClient = null; while (!done) { // ESTABLISH CONNECTION ------------------------------------------------------------------------------------- hostName = GetIpAddress(hostName); if (hostName == "") { Console.WriteLine("Unable to determine server IP address, try again? (y,[n])"); if (Console.ReadLine().ToLower().Contains("y")) { continue; } else { done = true; } break; } port = GetPort(port); myClient = GetClientConnection(hostName, port); if (myClient == null) { Console.WriteLine("Unable to connect to server, try again? (y,[n])"); if (Console.ReadLine().ToLower().Contains("y")) { continue; } else { done = true; } break; } Console.WriteLine("Connected to the Server!\n"); Console.WriteLine("==================================================================\n"); // SET UP ASYNC LISTENER FOR INPUT ------------------------------------------------------------------------------------- ConnectionMetadata connection = new ConnectionMetadata(myClient.Client); myClient.Client.BeginReceive(connection.Buffer, 0, ConnectionMetadata.BufferSize, 0, new AsyncCallback(OnReceiveData), connection); // ESTABLISH STREAM ------------------------------------------------------------------------------------- using NetworkStream SteamToServer = myClient.GetStream(); { byte[] data = new byte[ConnectionMetadata.BufferSize]; string userInput; // MAIN OUTPUT LOOP ------------------------------------------------------------------------------------- while (!done) { userInput = Console.ReadLine(); try { switch (userInput) { case "disconnect": case "dcon": case "exit": case "quit": userInput = "/disconnect"; SteamToServer.Write(Encoding.ASCII.GetBytes(userInput), 0, userInput.Length); Console.WriteLine("Disconnecting from server..."); done = true; break; default: if (userInput == "") { userInput = " "; } SteamToServer.Write(Encoding.ASCII.GetBytes(userInput), 0, userInput.Length); break; } } catch (IOException) { Console.Write("\n\nLost connection to server!\n\nReconnect? (y,[n])"); if (Console.ReadLine().ToLower().Contains("y")) { done = false; break; } else { done = true; break; } } SteamToServer.Flush(); } } } if (myClient != null) { myClient.Close(); } System.Console.WriteLine("Program gracefully terminated."); }
/// <summary> /// Adds a new connection to the list of tracked connections. /// </summary> /// <param name="connection">The connection to be added.</param> public bool AddConnection(ITrackingConnection connection) { if (connection == null) { throw new ArgumentNullException("connection"); } var newMetadata = new ConnectionMetadata(connection); ConnectionMetadata oldMetadata = null; bool isNewConnection = true; _connections.AddOrUpdate(connection.ConnectionId, newMetadata, (key, old) => { oldMetadata = old; return newMetadata; }); if (oldMetadata != null) { Trace.TraceInformation("Connection exists. Closing previous connection. Old=({0}, {1}) New=({2})", oldMetadata.Connection.IsAlive, oldMetadata.Connection.Url, connection.Url); // Kick out the older connection. This should only happen when // a previous connection attempt fails on the client side (e.g. transport fallback). EndConnection(oldMetadata); // If we have old metadata this isn't a new connection isNewConnection = false; } else { Trace.TraceInformation("Connection is New=({0}).", connection.Url); } lock (_counterLock) { _counters.ConnectionsCurrent.RawValue = _connections.Count; } // Set the initial connection time newMetadata.Initial = DateTime.UtcNow; // Register for disconnect cancellation newMetadata.Registration = connection.CancellationToken.SafeRegister(OnConnectionEnded, newMetadata); return isNewConnection; }
private void OnConnectionEnded(ConnectionMetadata metadata) { Trace.TraceInformation("OnConnectionEnded({0})", metadata.Connection.ConnectionId); // Release the request metadata.Connection.ReleaseRequest(); if (metadata.Registration != null) { metadata.Registration.Dispose(); } }
private static void EndConnection(ConnectionMetadata metadata) { // End the connection metadata.Connection.End(); // Dispose of the registration if (metadata.Registration != null) { metadata.Registration.Dispose(); } }
public EmailService(ConnectionMetadata connectionMetadata, ILogger <EmailService> logger) { _connectionMetadata = connectionMetadata; _logger = logger; }
private void CheckTimeoutAndKeepAlive(ConnectionMetadata metadata) { if (RaiseTimeout(metadata)) { // If we're past the expiration time then just timeout the connection metadata.Connection.Timeout(); } else { // The connection is still alive so we need to keep it alive with a server side "ping". // This is for scenarios where networking hardware (proxies, loadbalancers) get in the way // of us handling timeout's or disconnects gracefully if (RaiseKeepAlive(metadata)) { Trace.TraceEvent(TraceEventType.Verbose, 0, "KeepAlive(" + metadata.Connection.ConnectionId + ")"); // Ensure delegate continues to use the C# Compiler static delegate caching optimization. metadata.Connection.KeepAlive().Catch((ex, state) => OnKeepAliveError(ex, state), Trace); } MarkConnection(metadata.Connection); } }
private void CheckTimeoutAndKeepAlive(ConnectionMetadata metadata) { if (RaiseTimeout(metadata)) { RemoveConnection(metadata.Connection); // If we're past the expiration time then just timeout the connection metadata.Connection.Timeout(); // End the connection metadata.Connection.End(); } else { // The connection is still alive so we need to keep it alive with a server side "ping". // This is for scenarios where networking hardware (proxies, loadbalancers) get in the way // of us handling timeout's or disconnects gracefully if (RaiseKeepAlive(metadata)) { Trace.TraceInformation("KeepAlive(" + metadata.Connection.ConnectionId + ")"); // If the keep alive send fails then kill the connection metadata.Connection.KeepAlive() .Catch(ex => { Trace.TraceInformation("Failed to send keep alive: " + ex.GetBaseException()); RemoveConnection(metadata.Connection); metadata.Connection.End(); }); metadata.UpdateKeepAlive(_configurationManager.KeepAlive); } MarkConnection(metadata.Connection); } }
private void CheckDisconnect(ConnectionMetadata metadata) { try { if (RaiseDisconnect(metadata)) { // Remove the connection from the list RemoveConnection(metadata.Connection); // Fire disconnect on the connection metadata.Connection.Disconnect(); } } catch (Exception ex) { // Swallow exceptions that might happen during disconnect Trace.TraceEvent(TraceEventType.Error, 0, "Raising Disconnect failed: {0}", ex); } }
public async Task TestGetTwin() { // Arrange const string Id = "id1"; var identity = Mock.Of <IIdentity>(i => i.Id == Id); var twinMessageConverter = new TwinMessageConverter(); var twinCollectionMessageConverter = new TwinCollectionMessageConverter(); var messageConverterProvider = new MessageConverterProvider( new Dictionary <Type, IMessageConverter>() { { typeof(Message), new DeviceClientMessageConverter() }, { typeof(Shared.Twin), twinMessageConverter }, { typeof(TwinCollection), twinCollectionMessageConverter } }); var edgeHubTokenProvider = new Mock <ITokenProvider>(); var clientWatcher = new ClientWatcher(); var clientProvider = new Mock <IClientProvider>(); clientProvider.Setup(c => c.Create(identity, edgeHubTokenProvider.Object, It.IsAny <ITransportSettings[]>(), Option.None <string>())) .Returns(() => new ThrowingClient(clientWatcher, 3)); var deviceScopeIdentitiesCache = new Mock <IDeviceScopeIdentitiesCache>(); deviceScopeIdentitiesCache.Setup(d => d.GetServiceIdentity(Id)) .ReturnsAsync( Option.Some( new ServiceIdentity( Id, "dummy", new List <string>(), new ServiceAuthentication(new SymmetricKeyAuthentication("foo", "bar")), ServiceIdentityStatus.Enabled))); deviceScopeIdentitiesCache.Setup(d => d.GetAuthChain(It.Is <string>(i => i == Id))) .ReturnsAsync(Option.Some(Id)); var edgeHubIdentity = Mock.Of <IIdentity>(); ConnectionMetadata connectionMetadata = new ConnectionMetadata("edgeProdInfo"); var metadataStore = new Mock <IMetadataStore>(); metadataStore.Setup(p => p.GetMetadata(Id)) .ReturnsAsync(connectionMetadata); var identityProvider = new Mock <IIdentityProvider>(); identityProvider.Setup(i => i.Create(Id)).Returns(identity); var credentialsCache = new Mock <ICredentialsCache>(); var edgeHub = new Mock <IEdgeHub>(); var connectionProvider = new CloudConnectionProvider( messageConverterProvider, 1, clientProvider.Object, Option.None <UpstreamProtocol>(), edgeHubTokenProvider.Object, deviceScopeIdentitiesCache.Object, credentialsCache.Object, edgeHubIdentity, TimeSpan.FromMinutes(10), false, TimeSpan.FromMinutes(10), false, Option.None <IWebProxy>(), metadataStore.Object, true); connectionProvider.BindEdgeHub(edgeHub.Object); var deviceConnectivityManager = Mock.Of <IDeviceConnectivityManager>(); var connectionManager = new ConnectionManager(connectionProvider, credentialsCache.Object, identityProvider.Object, deviceConnectivityManager); // Act Option <ICloudProxy> cloudProxyOption = await connectionManager.GetCloudConnection(Id); // Assert Assert.True(cloudProxyOption.HasValue); ICloudProxy cloudProxy = cloudProxyOption.OrDefault(); Assert.True(cloudProxy.IsActive); // Act await RunGetTwin(cloudProxy, 10); // Assert Assert.Equal(5, clientWatcher.OpenAsyncCount); Assert.True(cloudProxy.IsActive); Assert.Equal(10, clientWatcher.GetTwinCount); }
private bool RaiseKeepAlive(ConnectionMetadata metadata) { var keepAlive = _configurationManager.KeepAlive; // Don't raise keep alive if it's set to 0 or the transport doesn't support // keep alive if (keepAlive == null || !metadata.Connection.SupportsKeepAlive) { return false; } // Raise keep alive if the keep alive value has passed return _heartbeatCount % (ulong)ConfigurationExtensions.HeartBeatsPerKeepAlive == 0; }
private void CheckTimeoutAndKeepAlive(ConnectionMetadata metadata) { if (RaiseTimeout(metadata)) { // If we're past the expiration time then just timeout the connection metadata.Connection.Timeout(); RemoveConnection(metadata.Connection); } else { // The connection is still alive so we need to keep it alive with a server side "ping". // This is for scenarios where networing hardware (proxies, loadbalancers) get in the way // of us handling timeout's or disconnects gracefully if (RaiseKeepAlive(metadata)) { metadata.Connection.KeepAlive().Catch(); metadata.UpdateKeepAlive(_configurationManager.KeepAlive); } MarkConnection(metadata.Connection); } }
private static void EndConnection(ConnectionMetadata metadata, bool disposeRegistration = true) { if (disposeRegistration) { // Dispose of the registration if (metadata.Registration != null) { metadata.Registration.Dispose(); } } // End the connection metadata.Connection.End(); }
private bool RaiseKeepAlive(ConnectionMetadata metadata) { TimeSpan? keepAlive = _configurationManager.KeepAlive; if (keepAlive == null) { return false; } // Raise keep alive if the keep alive value has passed return DateTime.UtcNow >= metadata.KeepAliveTime; }
public async Task <Try <ICloudConnection> > Connect(IIdentity identity, Action <string, CloudConnectionStatus> connectionStatusChangedHandler) { Preconditions.CheckNotNull(identity, nameof(identity)); try { var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), identity.Id); Option <ServiceIdentity> serviceIdentity = (await this.deviceScopeIdentitiesCache.GetServiceIdentity(identity.Id)) .Filter(s => s.Status == ServiceIdentityStatus.Enabled); string authChain = string.Empty; if (this.nestedEdgeEnabled) { Option <string> authChainMaybe = await this.deviceScopeIdentitiesCache.GetAuthChain(identity.Id); authChain = authChainMaybe.Expect(() => new InvalidOperationException($"No auth chain for the client identity: {identity.Id}")); } ITransportSettings[] transportSettings = GetTransportSettings( this.upstreamProtocol, this.connectionPoolSize, this.proxy, this.useServerHeartbeat, authChain); return(await serviceIdentity .Map( async si => { Events.CreatingCloudConnectionOnBehalfOf(identity); ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(identity.Id); string productInfo = connectionMetadata.EdgeProductInfo; Option <string> modelId = connectionMetadata.ModelId; ICloudConnection cc = await CloudConnection.Create( identity, connectionStatusChangedHandler, transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(identity); return Try.Success(cc); }) .GetOrElse( async() => { Events.ServiceIdentityNotFound(identity); Option <IClientCredentials> clientCredentials = await this.credentialsCache.Get(identity); return await clientCredentials .Map(cc => this.Connect(cc, connectionStatusChangedHandler)) .GetOrElse(() => throw new InvalidOperationException($"Unable to find identity {identity.Id} in device scopes cache or credentials cache")); })); } catch (Exception ex) { Events.ErrorCreatingCloudConnection(identity, ex); return(Try <ICloudConnection> .Failure(ex)); } }
private void CheckDisconnect(ConnectionMetadata metadata) { try { if (RaiseDisconnect(metadata)) { // Remove the connection from the list RemoveConnection(metadata.Connection); // Fire disconnect on the connection metadata.Connection.Disconnect(); } } catch (Exception ex) { // Swallow exceptions that might happen during disconnect Logger.LogError(String.Format("Raising Disconnect failed: {0}", ex)); } }
public async Task <Try <ICloudConnection> > Connect(IClientCredentials clientCredentials, Action <string, CloudConnectionStatus> connectionStatusChangedHandler) { Preconditions.CheckNotNull(clientCredentials, nameof(clientCredentials)); try { Events.CreatingCloudConnectionUsingClientCredentials(clientCredentials); var cloudListener = new CloudListener(this.edgeHub.Expect(() => new InvalidOperationException("EdgeHub reference should not be null")), clientCredentials.Identity.Id); ConnectionMetadata connectionMetadata = await this.metadataStore.GetMetadata(clientCredentials.Identity.Id); string productInfo = connectionMetadata.EdgeProductInfo; Option <string> modelId = clientCredentials.ModelId.HasValue ? clientCredentials.ModelId : connectionMetadata.ModelId; string authChain = string.Empty; if (this.nestedEdgeEnabled) { Option <string> authChainMaybe = await this.deviceScopeIdentitiesCache.GetAuthChain(clientCredentials.Identity.Id); // It's possible to have no auth-chain for out-of-scope leaf devices connecting through // us as a gateway. In this case we let the upstream connection happen anyways, as any // unauthorized attempt here would be denied by IoTHub. authChain = authChainMaybe.OrDefault(); } // Get the transport settings ITransportSettings[] transportSettings = GetTransportSettings( this.upstreamProtocol, this.connectionPoolSize, this.proxy, this.useServerHeartbeat, authChain); if (this.edgeHubIdentity.Id.Equals(clientCredentials.Identity.Id)) { ICloudConnection cc = await CloudConnection.Create( clientCredentials.Identity, connectionStatusChangedHandler, transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.edgeHubTokenProvider, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(clientCredentials.Identity); return(Try.Success(cc)); } else if (clientCredentials is ITokenCredentials clientTokenCredentails) { ICloudConnection cc = await ClientTokenCloudConnection.Create( clientTokenCredentails, connectionStatusChangedHandler, transportSettings, this.messageConverterProvider, this.clientProvider, cloudListener, this.idleTimeout, this.closeOnIdleTimeout, this.operationTimeout, productInfo, modelId); Events.SuccessCreatingCloudConnection(clientCredentials.Identity); return(Try.Success(cc)); } else { throw new InvalidOperationException($"Cannot connect using client credentials of type {clientCredentials.AuthenticationType} for identity {clientCredentials.Identity.Id}"); } } catch (Exception ex) { Events.ErrorCreatingCloudConnection(clientCredentials.Identity, ex); return(Try <ICloudConnection> .Failure(ex)); } }
private void CheckDisconnect(ConnectionMetadata metadata) { try { if (RaiseDisconnect(metadata)) { // Remove the connection from the list RemoveConnection(metadata.Connection); // Fire disconnect on the connection metadata.Connection.Disconnect(); } } catch { // Swallow exceptions that might happen during disconnect } }