//---------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Runtime; using System.Runtime.Diagnostics; using System.ServiceModel; using System.ServiceModel.Diagnostics; using System.ServiceModel.Diagnostics.Application; // code that pools items and closes/aborts them as necessary. // shared by IConnection and IChannel users abstract class CommunicationPool where TKey : class where TItem : class { Dictionary endpointPools; int maxCount; int openCount; // need to make sure we prune over a certain number of endpoint pools int pruneAccrual; const int pruneThreshold = 30; protected CommunicationPool(int maxCount) { this.maxCount = maxCount; this.endpointPools = new Dictionary(); this.openCount = 1; } public int MaxIdleConnectionPoolCount { get { return this.maxCount; } } protected object ThisLock { get { return this; } } protected abstract void AbortItem(TItem item); [Fx.Tag.Throws(typeof(CommunicationException), "A communication exception occurred closing this item")] [Fx.Tag.Throws(typeof(TimeoutException), "Timed out trying to close this item")] protected abstract void CloseItem(TItem item, TimeSpan timeout); protected abstract void CloseItemAsync(TItem item, TimeSpan timeout); protected abstract TKey GetPoolKey(EndpointAddress address, Uri via); protected virtual EndpointConnectionPool CreateEndpointConnectionPool(TKey key) { return new EndpointConnectionPool(this, key); } public bool Close(TimeSpan timeout) { lock (ThisLock) { if (openCount <= 0) { return true; } openCount--; if (openCount == 0) { this.OnClose(timeout); return true; } return false; } } List PruneIfNecessary() { List itemsToClose = null; pruneAccrual++; if (pruneAccrual > pruneThreshold) { pruneAccrual = 0; itemsToClose = new List(); // first prune the connection pool contents foreach (EndpointConnectionPool pool in endpointPools.Values) { pool.Prune(itemsToClose); } // figure out which connection pools are now empty List endpointKeysToRemove = null; foreach (KeyValuePair poolEntry in endpointPools) { if (poolEntry.Value.CloseIfEmpty()) { if (endpointKeysToRemove == null) { endpointKeysToRemove = new List(); } endpointKeysToRemove.Add(poolEntry.Key); } } // and then prune the connection pools themselves if (endpointKeysToRemove != null) { for (int i = 0; i < endpointKeysToRemove.Count; i++) { endpointPools.Remove(endpointKeysToRemove[i]); } } } return itemsToClose; } EndpointConnectionPool GetEndpointPool(TKey key, TimeSpan timeout) { EndpointConnectionPool result = null; List itemsToClose = null; lock (ThisLock) { if (!endpointPools.TryGetValue(key, out result)) { itemsToClose = PruneIfNecessary(); result = CreateEndpointConnectionPool(key); endpointPools.Add(key, result); } } Fx.Assert(result != null, "EndpointPool must be non-null at this point"); if (itemsToClose != null && itemsToClose.Count > 0) { // allocate half the remaining timeout for our g----ful shutdowns TimeoutHelper timeoutHelper = new TimeoutHelper(TimeoutHelper.Divide(timeout, 2)); for (int i = 0; i < itemsToClose.Count; i++) { result.CloseIdleConnection(itemsToClose[i], timeoutHelper.RemainingTime()); } } return result; } public bool TryOpen() { lock (ThisLock) { if (openCount <= 0) { // can't reopen connection pools since the registry purges them on close return false; } else { openCount++; return true; } } } protected virtual void OnClosed() { } void OnClose(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); foreach (EndpointConnectionPool pool in endpointPools.Values) { try { pool.Close(timeoutHelper.RemainingTime()); } catch (CommunicationException exception) { if (DiagnosticUtility.ShouldTraceError) { TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.ConnectionPoolCloseException, SR.GetString(SR.TraceCodeConnectionPoolCloseException), this, exception); } } catch (TimeoutException exception) { if (TD.CloseTimeoutIsEnabled()) { TD.CloseTimeout(exception.Message); } if (DiagnosticUtility.ShouldTraceError) { TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.ConnectionPoolCloseException, SR.GetString(SR.TraceCodeConnectionPoolCloseException), this, exception); } } } endpointPools.Clear(); } public void AddConnection(TKey key, TItem connection, TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); EndpointConnectionPool endpointPool = GetEndpointPool(key, timeoutHelper.RemainingTime()); endpointPool.AddConnection(connection, timeoutHelper.RemainingTime()); } public TItem TakeConnection(EndpointAddress address, Uri via, TimeSpan timeout, out TKey key) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); key = this.GetPoolKey(address, via); EndpointConnectionPool endpointPool = GetEndpointPool(key, timeoutHelper.RemainingTime()); return endpointPool.TakeConnection(timeoutHelper.RemainingTime()); } public void ReturnConnection(TKey key, TItem connection, bool connectionIsStillGood, TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); EndpointConnectionPool endpointPool = GetEndpointPool(key, timeoutHelper.RemainingTime()); endpointPool.ReturnConnection(connection, connectionIsStillGood, timeoutHelper.RemainingTime()); } // base class for our collection of Idle connections protected abstract class IdleConnectionPool { public abstract int Count { get; } public abstract bool Add(TItem item); public abstract bool Return(TItem item); public abstract TItem Take(out bool closeItem); } protected class EndpointConnectionPool { TKey key; List busyConnections; bool closed; IdleConnectionPool idleConnections; CommunicationPool parent; public EndpointConnectionPool(CommunicationPool parent, TKey key) { this.key = key; this.parent = parent; this.busyConnections = new List(); } protected TKey Key { get { return this.key; } } IdleConnectionPool IdleConnections { get { if (idleConnections == null) { idleConnections = GetIdleConnectionPool(); } return idleConnections; } } protected CommunicationPool Parent { get { return this.parent; } } protected object ThisLock { get { return this; } } // close down the pool if empty public bool CloseIfEmpty() { lock (ThisLock) { if (!closed) { if (busyConnections.Count > 0) { return false; } if (idleConnections != null && idleConnections.Count > 0) { return false; } closed = true; } } return true; } protected virtual void AbortItem(TItem item) { parent.AbortItem(item); } [Fx.Tag.Throws(typeof(CommunicationException), "A communication exception occurred closing this item")] [Fx.Tag.Throws(typeof(TimeoutException), "Timed out trying to close this item")] protected virtual void CloseItem(TItem item, TimeSpan timeout) { parent.CloseItem(item, timeout); } protected virtual void CloseItemAsync(TItem item, TimeSpan timeout) { parent.CloseItemAsync(item, timeout); } public void Abort() { if (closed) { return; } List idleItemsToClose = null; lock (ThisLock) { if (closed) return; closed = true; idleItemsToClose = SnapshotIdleConnections(); } AbortConnections(idleItemsToClose); } [Fx.Tag.Throws(typeof(CommunicationException), "A communication exception occurred closing this item")] [Fx.Tag.Throws(typeof(TimeoutException), "Timed out trying to close this item")] public void Close(TimeSpan timeout) { List itemsToClose = null; lock (ThisLock) { if (closed) return; closed = true; itemsToClose = SnapshotIdleConnections(); } try { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); for (int i = 0; i < itemsToClose.Count; i++) { this.CloseItem(itemsToClose[i], timeoutHelper.RemainingTime()); } itemsToClose.Clear(); } finally { AbortConnections(itemsToClose); } } void AbortConnections(List idleItemsToClose) { for (int i = 0; i < idleItemsToClose.Count; i++) { this.AbortItem(idleItemsToClose[i]); } for (int i = 0; i < busyConnections.Count; i++) { this.AbortItem(busyConnections[i]); } busyConnections.Clear(); } // must call under lock (ThisLock) since we are calling IdleConnections.Take() List SnapshotIdleConnections() { List itemsToClose = new List(); bool dummy; for (;;) { TItem item = IdleConnections.Take(out dummy); if (item == null) break; itemsToClose.Add(item); } return itemsToClose; } public void AddConnection(TItem connection, TimeSpan timeout) { bool closeConnection = false; lock (ThisLock) { if (!closed) { if (!IdleConnections.Add(connection)) { closeConnection = true; } } else { closeConnection = true; } } if (closeConnection) { CloseIdleConnection(connection, timeout); } } protected virtual IdleConnectionPool GetIdleConnectionPool() { return new PoolIdleConnectionPool(parent.MaxIdleConnectionPoolCount); } public virtual void Prune(List itemsToClose) { } public TItem TakeConnection(TimeSpan timeout) { TItem item = null; List itemsToClose = null; lock (ThisLock) { if (closed) return null; bool closeItem; while (true) { item = IdleConnections.Take(out closeItem); if (item == null) { break; } if (!closeItem) { busyConnections.Add(item); break; } if (itemsToClose == null) { itemsToClose = new List(); } itemsToClose.Add(item); } } // cleanup any stale items accrued from IdleConnections if (itemsToClose != null) { // and only allocate half the timeout passed in for our g----ful shutdowns TimeoutHelper timeoutHelper = new TimeoutHelper(TimeoutHelper.Divide(timeout, 2)); for (int i = 0; i < itemsToClose.Count; i++) { CloseIdleConnection(itemsToClose[i], timeoutHelper.RemainingTime()); } } if (TD.ConnectionPoolMissIsEnabled()) { if (item == null && busyConnections != null) { TD.ConnectionPoolMiss(key != null ? key.ToString() : string.Empty, busyConnections.Count); } } return item; } public void ReturnConnection(TItem connection, bool connectionIsStillGood, TimeSpan timeout) { bool closeConnection = false; bool abortConnection = false; lock (ThisLock) { if (!closed) { if (busyConnections.Remove(connection) && connectionIsStillGood) { if (!IdleConnections.Return(connection)) { closeConnection = true; } } else { abortConnection = true; } } else { abortConnection = true; } } if (closeConnection) { CloseIdleConnection(connection, timeout); } else if (abortConnection) { this.AbortItem(connection); OnConnectionAborted(); } } public void CloseIdleConnection(TItem connection, TimeSpan timeout) { bool throwing = true; try { this.CloseItemAsync(connection, timeout); throwing = false; } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); } finally { if (throwing) { this.AbortItem(connection); } } } protected virtual void OnConnectionAborted() { } protected class PoolIdleConnectionPool : IdleConnectionPool { Pool idleConnections; int maxCount; public PoolIdleConnectionPool(int maxCount) { this.idleConnections = new Pool(maxCount); this.maxCount = maxCount; } public override int Count { get { return idleConnections.Count; } } public override bool Add(TItem connection) { return ReturnToPool(connection); } public override bool Return(TItem connection) { return ReturnToPool(connection); } bool ReturnToPool(TItem connection) { bool result = this.idleConnections.Return(connection); if (!result) { if (TD.MaxOutboundConnectionsPerEndpointExceededIsEnabled()) { TD.MaxOutboundConnectionsPerEndpointExceeded(SR.GetString(SR.TraceCodeConnectionPoolMaxOutboundConnectionsPerEndpointQuotaReached, maxCount)); } if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.ConnectionPoolMaxOutboundConnectionsPerEndpointQuotaReached, SR.GetString(SR.TraceCodeConnectionPoolMaxOutboundConnectionsPerEndpointQuotaReached, maxCount), this); } } else if (TD.OutboundConnectionsPerEndpointRatioIsEnabled()) { TD.OutboundConnectionsPerEndpointRatio(this.idleConnections.Count, maxCount); } return result; } public override TItem Take(out bool closeItem) { closeItem = false; TItem ret = this.idleConnections.Take(); if (TD.OutboundConnectionsPerEndpointRatioIsEnabled()) { TD.OutboundConnectionsPerEndpointRatio(this.idleConnections.Count, maxCount); } return ret; } } } } // all our connection pools support Idling out of connections and lease timeout // (though Named Pipes doesn't leverage the lease timeout) abstract class ConnectionPool : IdlingCommunicationPool { int connectionBufferSize; TimeSpan maxOutputDelay; string name; protected ConnectionPool(IConnectionOrientedTransportChannelFactorySettings settings, TimeSpan leaseTimeout) : base(settings.MaxOutboundConnectionsPerEndpoint, settings.IdleTimeout, leaseTimeout) { this.connectionBufferSize = settings.ConnectionBufferSize; this.maxOutputDelay = settings.MaxOutputDelay; this.name = settings.ConnectionPoolGroupName; } public string Name { get { return this.name; } } protected override void AbortItem(IConnection item) { item.Abort(); } protected override void CloseItem(IConnection item, TimeSpan timeout) { item.Close(timeout, false); } protected override void CloseItemAsync(IConnection item, TimeSpan timeout) { item.Close(timeout, true); } public virtual bool IsCompatible(IConnectionOrientedTransportChannelFactorySettings settings) { return ( (this.name == settings.ConnectionPoolGroupName) && (this.connectionBufferSize == settings.ConnectionBufferSize) && (this.MaxIdleConnectionPoolCount == settings.MaxOutboundConnectionsPerEndpoint) && (this.IdleTimeout == settings.IdleTimeout) && (this.maxOutputDelay == settings.MaxOutputDelay) ); } } // Helper class used to manage the lifetime of a connection relative to its pool. abstract class ConnectionPoolHelper { IConnectionInitiator connectionInitiator; ConnectionPool connectionPool; Uri via; bool closed; // key for rawConnection in the connection pool string connectionKey; // did rawConnection originally come from connectionPool? bool isConnectionFromPool; // the "raw" connection that should be stored in the pool IConnection rawConnection; // the "upgraded" connection built on top of the "raw" connection to be used for I/O IConnection upgradedConnection; EventTraceActivity eventTraceActivity; public ConnectionPoolHelper(ConnectionPool connectionPool, IConnectionInitiator connectionInitiator, Uri via) { this.connectionInitiator = connectionInitiator; this.connectionPool = connectionPool; this.via = via; } object ThisLock { get { return this; } } protected EventTraceActivity EventTraceActivity { get { if (this.eventTraceActivity == null) { this.eventTraceActivity = EventTraceActivity.GetFromThreadOrCreate(); } return this.eventTraceActivity; } } protected abstract IConnection AcceptPooledConnection(IConnection connection, ref TimeoutHelper timeoutHelper); protected abstract IAsyncResult BeginAcceptPooledConnection(IConnection connection, ref TimeoutHelper timeoutHelper, AsyncCallback callback, object state); protected abstract IConnection EndAcceptPooledConnection(IAsyncResult result); protected abstract TimeoutException CreateNewConnectionTimeoutException(TimeSpan timeout, TimeoutException innerException); public IAsyncResult BeginEstablishConnection(TimeSpan timeout, AsyncCallback callback, object state) { return new EstablishConnectionAsyncResult(this, timeout, callback, state); } public IConnection EndEstablishConnection(IAsyncResult result) { return EstablishConnectionAsyncResult.End(result); } IConnection TakeConnection(TimeSpan timeout) { return this.connectionPool.TakeConnection(null, this.via, timeout, out this.connectionKey); } public IConnection EstablishConnection(TimeSpan timeout) { TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); IConnection localRawConnection = null; IConnection localUpgradedConnection = null; bool localIsConnectionFromPool = true; EventTraceActivity localEventTraceActivity = this.EventTraceActivity; if (TD.EstablishConnectionStartIsEnabled()) { TD.EstablishConnectionStart(localEventTraceActivity, this.via != null ? this.via.AbsoluteUri : string.Empty); } // first try and use a connection from our pool (and use it if we successfully receive an ACK) while (localIsConnectionFromPool) { localRawConnection = this.TakeConnection(timeoutHelper.RemainingTime()); if (localRawConnection == null) { localIsConnectionFromPool = false; } else { bool preambleSuccess = false; try { localUpgradedConnection = AcceptPooledConnection(localRawConnection, ref timeoutHelper); preambleSuccess = true; break; } catch (CommunicationException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); // CommmunicationException is ok since it was a cached connection of unknown state } catch (TimeoutException e) { if (TD.OpenTimeoutIsEnabled()) { TD.OpenTimeout(e.Message); } DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); // ditto for TimeoutException } finally { if (!preambleSuccess) { if (TD.ConnectionPoolPreambleFailedIsEnabled()) { TD.ConnectionPoolPreambleFailed(localEventTraceActivity); } if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent( TraceEventType.Information, TraceCode.FailedAcceptFromPool, SR.GetString( SR.TraceCodeFailedAcceptFromPool, timeoutHelper.RemainingTime())); } // This cannot throw TimeoutException since isConnectionStillGood is false (doesn't attempt a Close). this.connectionPool.ReturnConnection(connectionKey, localRawConnection, false, TimeSpan.Zero); } } } } // if there isn't anything in the pool, we need to use a new connection if (!localIsConnectionFromPool) { bool success = false; TimeSpan connectTimeout = timeoutHelper.RemainingTime(); try { try { localRawConnection = this.connectionInitiator.Connect(this.via, connectTimeout); } catch (TimeoutException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateNewConnectionTimeoutException( connectTimeout, e)); } this.connectionInitiator = null; localUpgradedConnection = AcceptPooledConnection(localRawConnection, ref timeoutHelper); success = true; } finally { if (!success) { connectionKey = null; if (localRawConnection != null) { localRawConnection.Abort(); } } } } SnapshotConnection(localUpgradedConnection, localRawConnection, localIsConnectionFromPool); if (TD.EstablishConnectionStopIsEnabled()) { TD.EstablishConnectionStop(localEventTraceActivity); } return localUpgradedConnection; } void SnapshotConnection(IConnection upgradedConnection, IConnection rawConnection, bool isConnectionFromPool) { lock (ThisLock) { if (closed) { upgradedConnection.Abort(); // cleanup our pool if necessary if (isConnectionFromPool) { this.connectionPool.ReturnConnection(this.connectionKey, rawConnection, false, TimeSpan.Zero); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( new CommunicationObjectAbortedException( SR.GetString(SR.OperationAbortedDuringConnectionEstablishment, this.via))); } else { this.upgradedConnection = upgradedConnection; this.rawConnection = rawConnection; this.isConnectionFromPool = isConnectionFromPool; } } } public void Abort() { ReleaseConnection(true, TimeSpan.Zero); } public void Close(TimeSpan timeout) { ReleaseConnection(false, timeout); } void ReleaseConnection(bool abort, TimeSpan timeout) { string localConnectionKey; IConnection localUpgradedConnection; IConnection localRawConnection; lock (ThisLock) { this.closed = true; localConnectionKey = this.connectionKey; localUpgradedConnection = this.upgradedConnection; localRawConnection = this.rawConnection; this.upgradedConnection = null; this.rawConnection = null; } if (localUpgradedConnection == null) { return; } try { if (this.isConnectionFromPool) { this.connectionPool.ReturnConnection(localConnectionKey, localRawConnection, !abort, timeout); } else { if (abort) { localUpgradedConnection.Abort(); } else { this.connectionPool.AddConnection(localConnectionKey, localRawConnection, timeout); } } } catch (CommunicationException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); localUpgradedConnection.Abort(); } } class EstablishConnectionAsyncResult : AsyncResult { ConnectionPoolHelper parent; TimeoutHelper timeoutHelper; IConnection currentConnection; IConnection rawConnection; bool newConnection; bool cleanupConnection; TimeSpan connectTimeout; static AsyncCallback onConnect; static AsyncCallback onProcessConnection = Fx.ThunkCallback(new AsyncCallback(OnProcessConnection)); EventTraceActivity eventTraceActivity; public EstablishConnectionAsyncResult(ConnectionPoolHelper parent, TimeSpan timeout, AsyncCallback callback, object state) : base(callback, state) { this.parent = parent; this.timeoutHelper = new TimeoutHelper(timeout); bool success = false; bool completeSelf = false; try { completeSelf = Begin(); success = true; } finally { if (!success) { Cleanup(); } } if (completeSelf) { Cleanup(); base.Complete(true); } } EventTraceActivity EventTraceActivity { get { if (this.eventTraceActivity == null) { this.eventTraceActivity = new EventTraceActivity(); } return this.eventTraceActivity; } } public static IConnection End(IAsyncResult result) { EstablishConnectionAsyncResult thisPtr = AsyncResult.End(result); if (TD.EstablishConnectionStopIsEnabled()) { TD.EstablishConnectionStop(thisPtr.EventTraceActivity); } return thisPtr.currentConnection; } bool Begin() { if (TD.EstablishConnectionStartIsEnabled()) { TD.EstablishConnectionStart(this.EventTraceActivity, this.parent.connectionKey); } IConnection connection = parent.TakeConnection(timeoutHelper.RemainingTime()); TrackConnection(connection); // first try and use a connection from our pool bool openingFromPool; if (OpenUsingConnectionPool(out openingFromPool)) { return true; } if (openingFromPool) { return false; } else { // if there isn't anything in the pool, we need to use a new connection return OpenUsingNewConnection(); } } bool OpenUsingConnectionPool(out bool openingFromPool) { openingFromPool = true; while (this.currentConnection != null) { bool snapshotCollection = false; try { if (ProcessConnection()) { snapshotCollection = true; } else { return false; } } catch (CommunicationException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); // CommunicationException is allowed for cached channels, as the connection // could be stale Cleanup(); // remove residual state } catch (TimeoutException e) { if (TD.OpenTimeoutIsEnabled()) { TD.OpenTimeout(e.Message); } DiagnosticUtility.TraceHandledException(e, TraceEventType.Information); // ditto for TimeoutException Cleanup(); // remove residual state } if (snapshotCollection) // connection succeeded. Snapshot and return { SnapshotConnection(); return true; } // previous connection failed, try again IConnection connection = parent.TakeConnection(timeoutHelper.RemainingTime()); TrackConnection(connection); } openingFromPool = false; return false; } bool OpenUsingNewConnection() { this.newConnection = true; IAsyncResult result; try { this.connectTimeout = timeoutHelper.RemainingTime(); if (onConnect == null) { onConnect = Fx.ThunkCallback(new AsyncCallback(OnConnect)); } result = parent.connectionInitiator.BeginConnect( parent.via, this.connectTimeout, onConnect, this); } catch (TimeoutException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( parent.CreateNewConnectionTimeoutException(connectTimeout, e)); } if (!result.CompletedSynchronously) { return false; } return HandleConnect(result); } bool HandleConnect(IAsyncResult connectResult) { try { TrackConnection(parent.connectionInitiator.EndConnect(connectResult)); } catch (TimeoutException e) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( parent.CreateNewConnectionTimeoutException(connectTimeout, e)); } if (ProcessConnection()) { // success. Snapshot and return SnapshotConnection(); return true; } else { return false; } } bool ProcessConnection() { IAsyncResult result = parent.BeginAcceptPooledConnection(this.rawConnection, ref timeoutHelper, onProcessConnection, this); if (!result.CompletedSynchronously) { return false; } return HandleProcessConnection(result); } bool HandleProcessConnection(IAsyncResult result) { this.currentConnection = parent.EndAcceptPooledConnection(result); this.cleanupConnection = false; return true; } void SnapshotConnection() { parent.SnapshotConnection(this.currentConnection, this.rawConnection, !this.newConnection); } void TrackConnection(IConnection connection) { this.cleanupConnection = true; this.rawConnection = connection; this.currentConnection = connection; } void Cleanup() { if (this.cleanupConnection) { if (this.newConnection) { if (this.currentConnection != null) { this.currentConnection.Abort(); this.currentConnection = null; } } else if (this.rawConnection != null) { if (DiagnosticUtility.ShouldTraceInformation) { TraceUtility.TraceEvent( TraceEventType.Information, TraceCode.FailedAcceptFromPool, SR.GetString( SR.TraceCodeFailedAcceptFromPool, this.timeoutHelper.RemainingTime())); } // This cannot throw TimeoutException since isConnectionStillGood is false (doesn't attempt a Close). parent.connectionPool.ReturnConnection(parent.connectionKey, this.rawConnection, false, timeoutHelper.RemainingTime()); this.currentConnection = null; this.rawConnection = null; } this.cleanupConnection = false; } } static void OnConnect(IAsyncResult result) { if (result.CompletedSynchronously) { return; } EstablishConnectionAsyncResult thisPtr = (EstablishConnectionAsyncResult)result.AsyncState; Exception completionException = null; bool completeSelf; try { completeSelf = thisPtr.HandleConnect(result); } #pragma warning suppress 56500 // Microsoft, transferring exception to another thread catch (Exception e) { if (Fx.IsFatal(e)) { throw; } completeSelf = true; completionException = e; } if (completeSelf) { thisPtr.Cleanup(); thisPtr.Complete(false, completionException); } } static void OnProcessConnection(IAsyncResult result) { if (result.CompletedSynchronously) { return; } EstablishConnectionAsyncResult thisPtr = (EstablishConnectionAsyncResult)result.AsyncState; Exception completionException = null; bool completeSelf; try { bool snapshotCollection = false; try { completeSelf = thisPtr.HandleProcessConnection(result); if (completeSelf) { snapshotCollection = true; } } catch (CommunicationException communicationException) { if (!thisPtr.newConnection) // CommunicationException is ok from our cache { DiagnosticUtility.TraceHandledException(communicationException, TraceEventType.Information); thisPtr.Cleanup(); completeSelf = thisPtr.Begin(); } else { completeSelf = true; completionException = communicationException; } } catch (TimeoutException timeoutException) { if (!thisPtr.newConnection) // TimeoutException is ok from our cache { if (TD.OpenTimeoutIsEnabled()) { TD.OpenTimeout(timeoutException.Message); } DiagnosticUtility.TraceHandledException(timeoutException, TraceEventType.Information); thisPtr.Cleanup(); completeSelf = thisPtr.Begin(); } else { completeSelf = true; completionException = timeoutException; } } if (snapshotCollection) { thisPtr.SnapshotConnection(); } } #pragma warning suppress 56500 // Microsoft, transferring exception to another thread catch (Exception e) { if (Fx.IsFatal(e)) { throw; } completeSelf = true; completionException = e; } if (completeSelf) { thisPtr.Cleanup(); thisPtr.Complete(false, completionException); } } } } }