private static SqlConnectionContainerHashHelper GetHashHelper(string connectionString, out SqlConnectionStringBuilder connectionStringBuilder, out DbConnectionPoolIdentity identity, out string user, string queue) { SqlConnectionContainerHashHelper helper; IntPtr ptr; Bid.NotificationsScopeEnter(out ptr, "<sc.SqlDependencyProcessDispatcher.GetHashString|DEP> %d#, queue: %ls", _staticInstance.ObjectID, queue); try { connectionStringBuilder = new SqlConnectionStringBuilder(connectionString); connectionStringBuilder.AsynchronousProcessing = true; connectionStringBuilder.Pooling = false; connectionStringBuilder.Enlist = false; if (queue != null) { connectionStringBuilder.ApplicationName = queue; } if (connectionStringBuilder.IntegratedSecurity) { identity = DbConnectionPoolIdentity.GetCurrent(); user = null; } else { identity = null; user = connectionStringBuilder.UserID; } helper = new SqlConnectionContainerHashHelper(identity, connectionStringBuilder.ConnectionString, queue, connectionStringBuilder); } finally { Bid.ScopeLeave(ref ptr); } return helper; }
internal static DbConnectionPoolIdentity GetCurrent() { DbConnectionPoolIdentity current; using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) { IntPtr token = identity.AccessToken.DangerousGetHandle(); bool isNetwork = identity.User.IsWellKnown(WellKnownSidType.NetworkSid); string sidString = identity.User.Value; // Win32NativeMethods.IsTokenRestricted will raise exception if the native call fails bool isRestricted = Win32NativeMethods.IsTokenRestrictedWrapper(token); var lastIdentity = s_lastIdentity; if ((lastIdentity != null) && (lastIdentity._sidString == sidString) && (lastIdentity._isRestricted == isRestricted) && (lastIdentity._isNetwork == isNetwork)) { current = lastIdentity; } else { current = new DbConnectionPoolIdentity(sidString, isRestricted, isNetwork); } } s_lastIdentity = current; return current; }
static internal DbConnectionPoolIdentity GetCurrent() { DbConnectionPoolIdentity current; using (WindowsIdentity identity = WindowsIdentity.GetCurrent()) { IntPtr token = identity.AccessToken.DangerousGetHandle(); bool isNetwork = identity.User.IsWellKnown(WellKnownSidType.NetworkSid); string sidString = identity.User.Value; // Win32NativeMethods.IsTokenRestricted will raise exception if the native call fails bool isRestricted = Win32NativeMethods.IsTokenRestrictedWrapper(token); var lastIdentity = s_lastIdentity; if ((lastIdentity != null) && (lastIdentity._sidString == sidString) && (lastIdentity._isRestricted == isRestricted) && (lastIdentity._isNetwork == isNetwork)) { current = lastIdentity; } else { current = new DbConnectionPoolIdentity(sidString, isRestricted, isNetwork); } } s_lastIdentity = current; return(current); }
internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactory) { object obj2 = null; if (this._poolGroupOptions != null) { DbConnectionPoolIdentity noIdentity = DbConnectionPoolIdentity.NoIdentity; if (this._poolGroupOptions.PoolByIdentity) { noIdentity = DbConnectionPoolIdentity.GetCurrent(); if (noIdentity.IsRestricted) { noIdentity = null; } } if (noIdentity != null) { obj2 = this._poolCollection[noIdentity]; if (obj2 == null) { DbConnectionPoolProviderInfo connectionPoolProviderInfo = connectionFactory.CreateConnectionPoolProviderInfo(this.ConnectionOptions); DbConnectionPool pool = new DbConnectionPool(connectionFactory, this, noIdentity, connectionPoolProviderInfo); lock (this) { HybridDictionary dictionary = this._poolCollection; obj2 = dictionary[noIdentity]; if ((obj2 == null) && this.MarkPoolGroupAsActive()) { pool.Startup(); HybridDictionary dictionary2 = new HybridDictionary(1 + dictionary.Count, false); foreach (DictionaryEntry entry in dictionary) { dictionary2.Add(entry.Key, entry.Value); } dictionary2.Add(noIdentity, pool); connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Increment(); this._poolCollection = dictionary2; this._poolCount = dictionary2.Count; obj2 = pool; pool = null; } } if (pool != null) { pool.Shutdown(); } } } } if (obj2 == null) { lock (this) { this.MarkPoolGroupAsActive(); } } return((DbConnectionPool)obj2); }
override public bool Equals(object value) { bool result = ((this == NoIdentity) || (this == value)); if (!result && (null != value)) { DbConnectionPoolIdentity that = ((DbConnectionPoolIdentity)value); result = ((_sidString == that._sidString) && (_isRestricted == that._isRestricted) && (_isNetwork == that._isNetwork)); } return(result); }
public override bool Equals(object value) { bool flag = (this == NoIdentity) || (this == value); if (!flag && (value != null)) { DbConnectionPoolIdentity identity = (DbConnectionPoolIdentity)value; flag = ((this._sidString == identity._sidString) && (this._isRestricted == identity._isRestricted)) && (this._isNetwork == identity._isNetwork); } return(flag); }
internal SqlInternalConnectionTds(DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, object providerInfo, string newPassword, SqlConnection owningObject, bool redirectedUserInstance) : base(connectionOptions) { this._instanceName = string.Empty; if (connectionOptions.UserInstance && InOutOfProcHelper.InProc) { throw SQL.UserInstanceNotAvailableInProc(); } this._identity = identity; this._poolGroupProviderInfo = (SqlConnectionPoolGroupProviderInfo) providerInfo; this._fResetConnection = connectionOptions.ConnectionReset; if (this._fResetConnection) { this._originalDatabase = connectionOptions.InitialCatalog; this._originalLanguage = connectionOptions.CurrentLanguage; } RuntimeHelpers.PrepareConstrainedRegions(); try { TimeoutTimer timeout = TimeoutTimer.StartSecondsTimeout(connectionOptions.ConnectTimeout); this.OpenLoginEnlist(owningObject, timeout, connectionOptions, newPassword, redirectedUserInstance); } catch (OutOfMemoryException) { base.DoomThisConnection(); throw; } catch (StackOverflowException) { base.DoomThisConnection(); throw; } catch (ThreadAbortException) { base.DoomThisConnection(); throw; } if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.ctor|ADV> %d#, constructed new TDS internal connection\n", base.ObjectID); } }
// only created by DbConnectionPoolGroup.GetConnectionPool internal DbConnectionPool( DbConnectionFactory connectionFactory, DbConnectionPoolGroup connectionPoolGroup, DbConnectionPoolIdentity identity, DbConnectionPoolProviderInfo?connectionPoolProviderInfo) { Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup"); if ((null != identity) && identity.IsRestricted) { throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToPoolOnRestrictedToken); } _state = State.Initializing; lock (s_random) { // Random.Next is not thread-safe _cleanupWait = s_random.Next(12, 24) * 10 * 1000; // 2-4 minutes in 10 sec intervals } _connectionFactory = connectionFactory; _connectionPoolGroup = connectionPoolGroup; _connectionPoolGroupOptions = connectionPoolGroup.PoolGroupOptions; _connectionPoolProviderInfo = connectionPoolProviderInfo; _identity = identity; _waitHandles = new PoolWaitHandles(); _errorWait = ERROR_WAIT_DEFAULT; _errorTimer = null; // No error yet. _objectList = new List <DbConnectionInternal>(MaxPoolSize); _poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback _state = State.Running; //_cleanupTimer & QueuePoolCreateRequest is delayed until DbConnectionPoolGroup calls // StartBackgroundCallbacks after pool is actually in the collection }
// although the new password is generally not used it must be passed to the c'tor // the new Login7 packet will always write out the new password (or a length of zero and no bytes if not present) // internal SqlInternalConnectionTds( DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, object providerInfo, bool redirectedUserInstance, SqlConnectionString userConnectionOptions = null, // NOTE: userConnectionOptions may be different to connectionOptions if the connection string has been expanded (see SqlConnectionString.Expand) SessionData reconnectSessionData = null, bool applyTransientFaultHandling = false) : base(connectionOptions) { #if DEBUG if (reconnectSessionData != null) { reconnectSessionData._debugReconnectDataApplied = true; } #endif Debug.Assert(reconnectSessionData == null || connectionOptions.ConnectRetryCount > 0, "Reconnect data supplied with CR turned off"); if (connectionOptions.ConnectRetryCount > 0) { _recoverySessionData = reconnectSessionData; if (reconnectSessionData == null) { _currentSessionData = new SessionData(); } else { _currentSessionData = new SessionData(_recoverySessionData); _originalDatabase = _recoverySessionData._initialDatabase; _originalLanguage = _recoverySessionData._initialLanguage; } } _identity = identity; _poolGroupProviderInfo = (SqlConnectionPoolGroupProviderInfo)providerInfo; _fResetConnection = connectionOptions.ConnectionReset; if (_fResetConnection && _recoverySessionData == null) { _originalDatabase = connectionOptions.InitialCatalog; _originalLanguage = connectionOptions.CurrentLanguage; } _timeoutErrorInternal = new SqlConnectionTimeoutErrorInternal(); _parserLock.Wait(canReleaseFromAnyThread: false); ThreadHasParserLockForClose = true; // In case of error, let ourselves know that we already own the parser lock try { var timeout = TimeoutTimer.StartSecondsTimeout(connectionOptions.ConnectTimeout); // If transient fault handling is enabled then we can retry the login upto the ConnectRetryCount. int connectionEstablishCount = applyTransientFaultHandling ? connectionOptions.ConnectRetryCount + 1 : 1; int transientRetryIntervalInMilliSeconds = connectionOptions.ConnectRetryInterval * 1000; // Max value of transientRetryInterval is 60*1000 ms. The max value allowed for ConnectRetryInterval is 60 for (int i = 0; i < connectionEstablishCount; i++) { try { OpenLoginEnlist(timeout, connectionOptions, redirectedUserInstance); break; } catch (SqlException sqlex) { if (i + 1 == connectionEstablishCount || !applyTransientFaultHandling || timeout.IsExpired || timeout.MillisecondsRemaining < transientRetryIntervalInMilliSeconds || !IsTransientError(sqlex)) { throw sqlex; } else { Thread.Sleep(transientRetryIntervalInMilliSeconds); } } } } finally { ThreadHasParserLockForClose = false; _parserLock.Release(); } }
private bool Start( string connectionString, out string server, out DbConnectionPoolIdentity identity, out string user, out string database, ref string queueService, string appDomainKey, SqlDependencyPerAppDomainDispatcher dispatcher, out bool errorOccurred, out bool appDomainStart, bool useDefaults) { IntPtr hscp; Bid.NotificationsScopeEnter(out hscp, "<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, queue: '%ls', appDomainKey: '%ls', perAppDomainDispatcher ID: '%d'", ObjectID, queueService, appDomainKey, dispatcher.ObjectID); try { Debug.Assert(this == _staticInstance, "Instance method called on non _staticInstance instance!"); server = null; // Reset out params. identity = null; user = null; database = null; errorOccurred = false; appDomainStart = false; lock (_sqlDependencyPerAppDomainDispatchers) { if (!_sqlDependencyPerAppDomainDispatchers.ContainsKey(appDomainKey)) { _sqlDependencyPerAppDomainDispatchers[appDomainKey] = dispatcher; } } SqlConnectionStringBuilder connectionStringBuilder = null; SqlConnectionContainerHashHelper hashHelper = GetHashHelper( connectionString, out connectionStringBuilder, out identity, out user, queueService); #if DEBUG SqlConnectionString connectionStringOptions = new SqlConnectionString(connectionStringBuilder.ConnectionString); Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> Modified connection string: '%ls'\n", connectionStringOptions.UsersConnectionStringForTrace()); #endif bool started = false; SqlConnectionContainer container = null; lock (_connectionContainers) { if (!_connectionContainers.ContainsKey(hashHelper)) { Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, hashtable miss, creating new container.\n", ObjectID); container = new SqlConnectionContainer(hashHelper, appDomainKey, useDefaults); _connectionContainers.Add(hashHelper, container); started = true; appDomainStart = true; } else { container = _connectionContainers[hashHelper]; Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, hashtable hit, container: %d\n", ObjectID, container.ObjectID); if (container.InErrorState) { Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, container: %d is in error state!\n", ObjectID, container.ObjectID); errorOccurred = true; // Set outparam errorOccurred true so we invalidate on Start(). } else { container.IncrementStartCount(appDomainKey, out appDomainStart); } } } if (useDefaults && !errorOccurred) { // Return server, database, and queue for use by SqlDependency. server = container.Server; database = container.Database; queueService = container.Queue; Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, default service: '%ls', server: '%ls', database: '%ls'\n", ObjectID, queueService, server, database); } Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, started: %d\n", ObjectID, started); return started; } finally { Bid.ScopeLeave(ref hscp); } }
// ------------ // Stop methods // ------------ internal bool Stop( string connectionString, out string server, out DbConnectionPoolIdentity identity, out string user, out string database, ref string queueService, string appDomainKey, out bool appDomainStop) { IntPtr hscp; Bid.NotificationsScopeEnter(out hscp, "<sc.SqlDependencyProcessDispatcher.Stop|DEP> %d#, queue: '%ls'", ObjectID, queueService); try { Debug.Assert(this == _staticInstance, "Instance method called on non _staticInstance instance!"); server = null; // Reset out param. identity = null; user = null; database = null; appDomainStop = false; SqlConnectionStringBuilder connectionStringBuilder = null; SqlConnectionContainerHashHelper hashHelper = GetHashHelper( connectionString, out connectionStringBuilder, out identity, out user, queueService); #if DEBUG SqlConnectionString connectionStringOptions = new SqlConnectionString(connectionStringBuilder.ConnectionString); Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Stop|DEP> Modified connection string: '%ls'\n", connectionStringOptions.UsersConnectionStringForTrace()); #endif bool stopped = false; lock (_connectionContainers) { if (_connectionContainers.ContainsKey(hashHelper)) { SqlConnectionContainer container = _connectionContainers[hashHelper]; Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Stop|DEP> %d#, hashtable hit, container: %d\n", ObjectID, container.ObjectID); server = container.Server; // Return server, database, and queue info for use by calling SqlDependency. database = container.Database; queueService = container.Queue; if (container.Stop(appDomainKey, out appDomainStop)) { // Stop can be blocking if refCount == 0 on container. stopped = true; _connectionContainers.Remove(hashHelper); // Remove from collection. } } else { Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Stop|DEP> %d#, hashtable miss.\n", ObjectID); } } Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Stop|DEP> %d#, stopped: %d\n", ObjectID, stopped); return stopped; } finally { Bid.ScopeLeave(ref hscp); } }
// ----------------------- // Various private methods // ----------------------- private static SqlConnectionContainerHashHelper GetHashHelper( string connectionString, out SqlConnectionStringBuilder connectionStringBuilder, out DbConnectionPoolIdentity identity, out string user, string queue) { IntPtr hscp; Bid.NotificationsScopeEnter(out hscp, "<sc.SqlDependencyProcessDispatcher.GetHashString|DEP> %d#, queue: %ls", _staticInstance.ObjectID, queue); try { // Force certain connection string properties to be used by SqlDependencyProcessDispatcher. // This logic is done here to enable us to have the complete connection string now to be used // for tracing as we flow through the logic. connectionStringBuilder = new SqlConnectionStringBuilder(connectionString); connectionStringBuilder.AsynchronousProcessing = true; connectionStringBuilder.Pooling = false; connectionStringBuilder.Enlist = false; connectionStringBuilder.ConnectRetryCount = 0; if (null != queue) { // User provided! connectionStringBuilder.ApplicationName = queue; // ApplicationName will be set to queue name. } if (connectionStringBuilder.IntegratedSecurity) { // Use existing identity infrastructure for error cases and proper hash value. identity = DbConnectionPoolIdentity.GetCurrent(); user = null; } else { identity = null; user = connectionStringBuilder.UserID; } return new SqlConnectionContainerHashHelper(identity, connectionStringBuilder.ConnectionString, queue, connectionStringBuilder); } finally { Bid.ScopeLeave(ref hscp); } }
// ------------- // Start methods // ------------- internal bool StartWithDefault( string connectionString, out string server, out DbConnectionPoolIdentity identity, out string user, out string database, ref string service, string appDomainKey, SqlDependencyPerAppDomainDispatcher dispatcher, out bool errorOccurred, out bool appDomainStart) { Debug.Assert(this == _staticInstance, "Instance method called on non _staticInstance instance!"); return Start( connectionString, out server, out identity, out user, out database, ref service, appDomainKey, dispatcher, out errorOccurred, out appDomainStart, true); }
internal bool Stop(string connectionString, out string server, out DbConnectionPoolIdentity identity, out string user, out string database, ref string queueService, string appDomainKey, out bool appDomainStop) { bool flag2; IntPtr ptr; Bid.NotificationsScopeEnter(out ptr, "<sc.SqlDependencyProcessDispatcher.Stop|DEP> %d#, queue: '%ls'", this.ObjectID, queueService); try { server = null; identity = null; user = null; database = null; appDomainStop = false; SqlConnectionStringBuilder connectionStringBuilder = null; SqlConnectionContainerHashHelper key = GetHashHelper(connectionString, out connectionStringBuilder, out identity, out user, queueService); bool flag = false; lock (this._connectionContainers) { if (this._connectionContainers.ContainsKey(key)) { SqlConnectionContainer container = this._connectionContainers[key]; Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Stop|DEP> %d#, hashtable hit, container: %d\n", this.ObjectID, container.ObjectID); server = container.Server; database = container.Database; queueService = container.Queue; if (container.Stop(appDomainKey, out appDomainStop)) { flag = true; this._connectionContainers.Remove(key); } } else { Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Stop|DEP> %d#, hashtable miss.\n", this.ObjectID); } } Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Stop|DEP> %d#, stopped: %d\n", this.ObjectID, flag); flag2 = flag; } finally { Bid.ScopeLeave(ref ptr); } return flag2; }
private SqlConnectionStringBuilder _connectionStringBuilder; // Not to be used for comparison! internal SqlConnectionContainerHashHelper(DbConnectionPoolIdentity identity, string connectionString, string queue, SqlConnectionStringBuilder connectionStringBuilder) { _identity = identity; _connectionString = connectionString; _queue = queue; _connectionStringBuilder = connectionStringBuilder; }
// only created by DbConnectionPoolGroup.GetConnectionPool internal DbConnectionPool( DbConnectionFactory connectionFactory, DbConnectionPoolGroup connectionPoolGroup, DbConnectionPoolIdentity identity, DbConnectionPoolProviderInfo connectionPoolProviderInfo) { Debug.Assert(null != connectionPoolGroup, "null connectionPoolGroup"); if ((null != identity) && identity.IsRestricted) { throw ADP.InternalError(ADP.InternalErrorCode.AttemptingToPoolOnRestrictedToken); } _state = State.Initializing; lock (s_random) { // Random.Next is not thread-safe _cleanupWait = s_random.Next(12, 24) * 10 * 1000; // 2-4 minutes in 10 sec intervals } _connectionFactory = connectionFactory; _connectionPoolGroup = connectionPoolGroup; _connectionPoolGroupOptions = connectionPoolGroup.PoolGroupOptions; _connectionPoolProviderInfo = connectionPoolProviderInfo; _identity = identity; _waitHandles = new PoolWaitHandles(); _errorWait = ERROR_WAIT_DEFAULT; _errorTimer = null; // No error yet. _objectList = new List<DbConnectionInternal>(MaxPoolSize); _poolCreateRequest = new WaitCallback(PoolCreateRequest); // used by CleanupCallback _state = State.Running; //_cleanupTimer & QueuePoolCreateRequest is delayed until DbConnectionPoolGroup calls // StartBackgroundCallbacks after pool is actually in the collection }
internal static DbConnectionPoolIdentity GetCurrent() { if (!ADP.IsWindowsNT) { return NoIdentity; } WindowsIdentity currentWindowsIdentity = GetCurrentWindowsIdentity(); IntPtr windowsIdentityToken = GetWindowsIdentityToken(currentWindowsIdentity); uint tokenInformationLength = 0x800; uint tokenString = 0; IntPtr zero = IntPtr.Zero; IntPtr stringSid = IntPtr.Zero; System.Data.Common.UnsafeNativeMethods.SetLastError(0); bool isRestricted = System.Data.Common.UnsafeNativeMethods.IsTokenRestricted(windowsIdentityToken); if (Marshal.GetLastWin32Error() != 0) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } DbConnectionPoolIdentity identity = null; RuntimeHelpers.PrepareConstrainedRegions(); try { bool flag; if (!System.Data.Common.UnsafeNativeMethods.CheckTokenMembership(windowsIdentityToken, NetworkSid, out flag)) { IntegratedSecurityError(1); } RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { zero = SafeNativeMethods.LocalAlloc(0, (IntPtr) tokenInformationLength); } if (IntPtr.Zero == zero) { throw new OutOfMemoryException(); } if (!System.Data.Common.UnsafeNativeMethods.GetTokenInformation(windowsIdentityToken, 1, zero, tokenInformationLength, ref tokenString)) { if (tokenString > tokenInformationLength) { tokenInformationLength = tokenString; RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { SafeNativeMethods.LocalFree(zero); zero = IntPtr.Zero; zero = SafeNativeMethods.LocalAlloc(0, (IntPtr) tokenInformationLength); } if (IntPtr.Zero == zero) { throw new OutOfMemoryException(); } if (!System.Data.Common.UnsafeNativeMethods.GetTokenInformation(windowsIdentityToken, 1, zero, tokenInformationLength, ref tokenString)) { IntegratedSecurityError(2); } } else { IntegratedSecurityError(3); } } currentWindowsIdentity.Dispose(); if (!System.Data.Common.UnsafeNativeMethods.ConvertSidToStringSidW(Marshal.ReadIntPtr(zero, 0), out stringSid)) { IntegratedSecurityError(4); } if (IntPtr.Zero == stringSid) { throw ADP.InternalError(ADP.InternalErrorCode.ConvertSidToStringSidWReturnedNull); } identity = new DbConnectionPoolIdentity(Marshal.PtrToStringUni(stringSid), isRestricted, flag); } finally { if (IntPtr.Zero != zero) { SafeNativeMethods.LocalFree(zero); zero = IntPtr.Zero; } if (IntPtr.Zero != stringSid) { SafeNativeMethods.LocalFree(stringSid); stringSid = IntPtr.Zero; } } return identity; }
// although the new password is generally not used it must be passed to the c'tor // the new Login7 packet will always write out the new password (or a length of zero and no bytes if not present) // internal SqlInternalConnectionTds( DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, object providerInfo, bool redirectedUserInstance, SqlConnectionString userConnectionOptions = null, // NOTE: userConnectionOptions may be different to connectionOptions if the connection string has been expanded (see SqlConnectionString.Expand) SessionData reconnectSessionData = null) : base(connectionOptions) { #if DEBUG if (reconnectSessionData != null) { reconnectSessionData._debugReconnectDataApplied = true; } #endif Debug.Assert(reconnectSessionData == null || connectionOptions.ConnectRetryCount > 0, "Reconnect data supplied with CR turned off"); if (connectionOptions.ConnectRetryCount > 0) { _recoverySessionData = reconnectSessionData; if (reconnectSessionData == null) { _currentSessionData = new SessionData(); } else { _currentSessionData = new SessionData(_recoverySessionData); _originalDatabase = _recoverySessionData._initialDatabase; _originalLanguage = _recoverySessionData._initialLanguage; } } _identity = identity; _poolGroupProviderInfo = (SqlConnectionPoolGroupProviderInfo)providerInfo; _fResetConnection = connectionOptions.ConnectionReset; if (_fResetConnection && _recoverySessionData == null) { _originalDatabase = connectionOptions.InitialCatalog; _originalLanguage = connectionOptions.CurrentLanguage; } _timeoutErrorInternal = new SqlConnectionTimeoutErrorInternal(); _parserLock.Wait(canReleaseFromAnyThread: false); ThreadHasParserLockForClose = true; // In case of error, let ourselves know that we already own the parser lock try { var timeout = TimeoutTimer.StartSecondsTimeout(connectionOptions.ConnectTimeout); OpenLoginEnlist(timeout, connectionOptions, redirectedUserInstance); } finally { ThreadHasParserLockForClose = false; _parserLock.Release(); } }
internal bool StartWithDefault(string connectionString, out string server, out DbConnectionPoolIdentity identity, out string user, out string database, ref string service, string appDomainKey, SqlDependencyPerAppDomainDispatcher dispatcher, out bool errorOccurred, out bool appDomainStart) { return this.Start(connectionString, out server, out identity, out user, out database, ref service, appDomainKey, dispatcher, out errorOccurred, out appDomainStart, true); }
static internal DbConnectionPoolIdentity GetCurrent() { // DEVNOTE: GetTokenInfo and EqualSID do not work on 9x. WindowsIdentity does not // work either on 9x. In fact, after checking with native there is no way // to validate the user on 9x, so simply don't. It is a known issue in // native, and we will handle this the same way. if (!ADP.IsWindowsNT) { return(NoIdentity); } WindowsIdentity identity = GetCurrentWindowsIdentity(); IntPtr token = GetWindowsIdentityToken(identity); // Free'd by WindowsIdentity. uint bufferLength = 2048; // Suggested default given by Greg Fee. uint lengthNeeded = 0; IntPtr tokenStruct = IntPtr.Zero; IntPtr SID; IntPtr sidStringBuffer = IntPtr.Zero; bool isNetwork; // Win32NativeMethods.IsTokenRestricted will raise exception if the native call fails bool isRestricted = Win32NativeMethods.IsTokenRestrictedWrapper(token); DbConnectionPoolIdentity current = null; RuntimeHelpers.PrepareConstrainedRegions(); try { if (!UnsafeNativeMethods.CheckTokenMembership(token, NetworkSid, out isNetwork)) { // will always fail with 0x8007051D if token is not an impersonation token IntegratedSecurityError(Win32_CheckTokenMembership); } RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // allocating memory and assigning to tokenStruct must happen tokenStruct = SafeNativeMethods.LocalAlloc(DbBuffer.LMEM_FIXED, (IntPtr)bufferLength); } if (IntPtr.Zero == tokenStruct) { throw new OutOfMemoryException(); } if (!UnsafeNativeMethods.GetTokenInformation(token, 1, tokenStruct, bufferLength, ref lengthNeeded)) { if (lengthNeeded > bufferLength) { bufferLength = lengthNeeded; RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // freeing token struct and setting tokenstruct to null must happen together // allocating memory and assigning to tokenStruct must happen SafeNativeMethods.LocalFree(tokenStruct); tokenStruct = IntPtr.Zero; // protect against LocalAlloc throwing an exception tokenStruct = SafeNativeMethods.LocalAlloc(DbBuffer.LMEM_FIXED, (IntPtr)bufferLength); } if (IntPtr.Zero == tokenStruct) { throw new OutOfMemoryException(); } if (!UnsafeNativeMethods.GetTokenInformation(token, 1, tokenStruct, bufferLength, ref lengthNeeded)) { IntegratedSecurityError(Win32_GetTokenInformation_1); } } else { IntegratedSecurityError(Win32_GetTokenInformation_2); } } identity.Dispose(); // Keep identity variable alive until after GetTokenInformation calls. SID = Marshal.ReadIntPtr(tokenStruct, 0); if (!UnsafeNativeMethods.ConvertSidToStringSidW(SID, out sidStringBuffer)) { IntegratedSecurityError(Win32_ConvertSidToStringSidW); } if (IntPtr.Zero == sidStringBuffer) { throw ADP.InternalError(ADP.InternalErrorCode.ConvertSidToStringSidWReturnedNull); } string sidString = Marshal.PtrToStringUni(sidStringBuffer); var lastIdentity = _lastIdentity; if ((lastIdentity != null) && (lastIdentity._sidString == sidString) && (lastIdentity._isRestricted == isRestricted) && (lastIdentity._isNetwork == isNetwork)) { current = lastIdentity; } else { current = new DbConnectionPoolIdentity(sidString, isRestricted, isNetwork); } } finally { // Marshal.FreeHGlobal does not have a ReliabilityContract if (IntPtr.Zero != tokenStruct) { SafeNativeMethods.LocalFree(tokenStruct); tokenStruct = IntPtr.Zero; } if (IntPtr.Zero != sidStringBuffer) { SafeNativeMethods.LocalFree(sidStringBuffer); sidStringBuffer = IntPtr.Zero; } } _lastIdentity = current; return(current); }
internal IdentityUserNamePair(DbConnectionPoolIdentity identity, string userName) { this._identity = identity; this._userName = userName; }
internal IdentityUserNamePair(DbConnectionPoolIdentity identity, string userName) { Debug.Assert( (identity == null && userName != null) || (identity != null && userName == null), "Unexpected arguments!"); _identity = identity; _userName = userName; }
// although the new password is generally not used it must be passed to the c'tor // the new Login7 packet will always write out the new password (or a length of zero and no bytes if not present) // internal SqlInternalConnectionTds( DbConnectionPoolIdentity identity, SqlConnectionString connectionOptions, SqlCredential credential, object providerInfo, string newPassword, SecureString newSecurePassword, bool redirectedUserInstance, SqlConnectionString userConnectionOptions = null, // NOTE: userConnectionOptions may be different to connectionOptions if the connection string has been expanded (see SqlConnectionString.Expand) SessionData reconnectSessionData = null, DbConnectionPool pool = null, string accessToken = null, bool applyTransientFaultHandling = false ) : base(connectionOptions) { #if DEBUG if (reconnectSessionData != null) { reconnectSessionData._debugReconnectDataApplied = true; } try { // use this to help validate this object is only created after the following permission has been previously demanded in the current codepath if (userConnectionOptions != null) { // As mentioned above, userConnectionOptions may be different to connectionOptions, so we need to demand on the correct connection string userConnectionOptions.DemandPermission(); } else { connectionOptions.DemandPermission(); } } catch(System.Security.SecurityException) { System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath"); throw; } #endif Debug.Assert(reconnectSessionData == null || connectionOptions.ConnectRetryCount > 0, "Reconnect data supplied with CR turned off"); _dbConnectionPool = pool; if (connectionOptions.ConnectRetryCount > 0) { _recoverySessionData = reconnectSessionData; if (reconnectSessionData == null) { _currentSessionData = new SessionData(); } else { _currentSessionData = new SessionData(_recoverySessionData); _originalDatabase = _recoverySessionData._initialDatabase; _originalLanguage = _recoverySessionData._initialLanguage; } } if (connectionOptions.UserInstance && InOutOfProcHelper.InProc) { throw SQL.UserInstanceNotAvailableInProc(); } if (accessToken != null) { _accessTokenInBytes = System.Text.Encoding.Unicode.GetBytes(accessToken); } _identity = identity; Debug.Assert(newSecurePassword != null || newPassword != null, "cannot have both new secure change password and string based change password to be null"); Debug.Assert(credential == null || (String.IsNullOrEmpty(connectionOptions.UserID) && String.IsNullOrEmpty(connectionOptions.Password)), "cannot mix the new secure password system and the connection string based password"); Debug.Assert(credential == null || !connectionOptions.IntegratedSecurity, "Cannot use SqlCredential and Integrated Security"); Debug.Assert(credential == null || !connectionOptions.ContextConnection, "Cannot use SqlCredential with context connection"); _poolGroupProviderInfo = (SqlConnectionPoolGroupProviderInfo)providerInfo; _fResetConnection = connectionOptions.ConnectionReset; if (_fResetConnection && _recoverySessionData == null) { _originalDatabase = connectionOptions.InitialCatalog; _originalLanguage = connectionOptions.CurrentLanguage; } timeoutErrorInternal = new SqlConnectionTimeoutErrorInternal(); _credential = credential; _parserLock.Wait(canReleaseFromAnyThread:false); ThreadHasParserLockForClose = true; // In case of error, let ourselves know that we already own the parser lock RuntimeHelpers.PrepareConstrainedRegions(); try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); RuntimeHelpers.PrepareConstrainedRegions(); try { tdsReliabilitySection.Start(); #else { #endif //DEBUG _timeout = TimeoutTimer.StartSecondsTimeout(connectionOptions.ConnectTimeout); // If transient fault handling is enabled then we can retry the login upto the ConnectRetryCount. int connectionEstablishCount = applyTransientFaultHandling ? connectionOptions.ConnectRetryCount + 1 : 1; int transientRetryIntervalInMilliSeconds = connectionOptions.ConnectRetryInterval * 1000; // Max value of transientRetryInterval is 60*1000 ms. The max value allowed for ConnectRetryInterval is 60 for (int i = 0; i < connectionEstablishCount; i++) { try { OpenLoginEnlist(_timeout, connectionOptions, credential, newPassword, newSecurePassword, redirectedUserInstance); break; } catch (SqlException sqlex) { if (i + 1 == connectionEstablishCount || !applyTransientFaultHandling || _timeout.IsExpired || _timeout.MillisecondsRemaining < transientRetryIntervalInMilliSeconds || !IsTransientError(sqlex)) { throw sqlex; } else { Thread.Sleep(transientRetryIntervalInMilliSeconds); } } } } #if DEBUG finally { tdsReliabilitySection.Stop(); } #endif //DEBUG } catch (System.OutOfMemoryException) { DoomThisConnection(); throw; } catch (System.StackOverflowException) { DoomThisConnection(); throw; } catch (System.Threading.ThreadAbortException) { DoomThisConnection(); throw; } finally { ThreadHasParserLockForClose = false; _parserLock.Release(); } if (Bid.AdvancedOn) { Bid.Trace("<sc.SqlInternalConnectionTds.ctor|ADV> %d#, constructed new TDS internal connection\n", ObjectID); } }
static internal DbConnectionPoolIdentity GetCurrent() { // DEVNOTE: GetTokenInfo and EqualSID do not work on 9x. WindowsIdentity does not // work either on 9x. In fact, after checking with native there is no way // to validate the user on 9x, so simply don't. It is a known issue in // native, and we will handle this the same way. if (!ADP.IsWindowsNT) { return NoIdentity; } WindowsIdentity identity = GetCurrentWindowsIdentity(); IntPtr token = GetWindowsIdentityToken(identity); // Free'd by WindowsIdentity. uint bufferLength = 2048; // Suggested default given by Greg Fee. uint lengthNeeded = 0; IntPtr tokenStruct = IntPtr.Zero; IntPtr SID; IntPtr sidStringBuffer = IntPtr.Zero; bool isNetwork; // Win32NativeMethods.IsTokenRestricted will raise exception if the native call fails bool isRestricted = Win32NativeMethods.IsTokenRestrictedWrapper(token); DbConnectionPoolIdentity current = null; RuntimeHelpers.PrepareConstrainedRegions(); try { if (!UnsafeNativeMethods.CheckTokenMembership(token, NetworkSid, out isNetwork)) { // will always fail with 0x8007051D if token is not an impersonation token IntegratedSecurityError(Win32_CheckTokenMembership); } RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // allocating memory and assigning to tokenStruct must happen tokenStruct = SafeNativeMethods.LocalAlloc(DbBuffer.LMEM_FIXED, (IntPtr)bufferLength); } if (IntPtr.Zero == tokenStruct) { throw new OutOfMemoryException(); } if (!UnsafeNativeMethods.GetTokenInformation(token, 1, tokenStruct, bufferLength, ref lengthNeeded)) { if (lengthNeeded > bufferLength) { bufferLength = lengthNeeded; RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // freeing token struct and setting tokenstruct to null must happen together // allocating memory and assigning to tokenStruct must happen SafeNativeMethods.LocalFree(tokenStruct); tokenStruct = IntPtr.Zero; // protect against LocalAlloc throwing an exception tokenStruct = SafeNativeMethods.LocalAlloc(DbBuffer.LMEM_FIXED, (IntPtr)bufferLength); } if (IntPtr.Zero == tokenStruct) { throw new OutOfMemoryException(); } if (!UnsafeNativeMethods.GetTokenInformation(token, 1, tokenStruct, bufferLength, ref lengthNeeded)) { IntegratedSecurityError(Win32_GetTokenInformation_1); } } else { IntegratedSecurityError(Win32_GetTokenInformation_2); } } identity.Dispose(); // Keep identity variable alive until after GetTokenInformation calls. SID = Marshal.ReadIntPtr(tokenStruct, 0); if (!UnsafeNativeMethods.ConvertSidToStringSidW(SID, out sidStringBuffer)) { IntegratedSecurityError(Win32_ConvertSidToStringSidW); } if (IntPtr.Zero == sidStringBuffer) { throw ADP.InternalError(ADP.InternalErrorCode.ConvertSidToStringSidWReturnedNull); } string sidString = Marshal.PtrToStringUni(sidStringBuffer); var lastIdentity = _lastIdentity; if ((lastIdentity != null) && (lastIdentity._sidString == sidString) && (lastIdentity._isRestricted == isRestricted) && (lastIdentity._isNetwork == isNetwork)) { current = lastIdentity; } else { current = new DbConnectionPoolIdentity(sidString, isRestricted, isNetwork); } } finally { // Marshal.FreeHGlobal does not have a ReliabilityContract if (IntPtr.Zero != tokenStruct) { SafeNativeMethods.LocalFree(tokenStruct); tokenStruct = IntPtr.Zero; } if (IntPtr.Zero != sidStringBuffer) { SafeNativeMethods.LocalFree(sidStringBuffer); sidStringBuffer = IntPtr.Zero; } } _lastIdentity = current; return current; }
internal DbConnectionPool GetConnectionPool(DbConnectionFactory connectionFactory) { // When this method returns null it indicates that the connection // factory should not use pooling. // We don't support connection pooling on Win9x; it lacks too // many of the APIs we require. // PoolGroupOptions will only be null when we're not supposed to pool // connections. DbConnectionPool pool = null; if (null != _poolGroupOptions) { Debug.Assert(ADP.IsWindowsNT, "should not be pooling on Win9x"); DbConnectionPoolIdentity currentIdentity = DbConnectionPoolIdentity.NoIdentity; if (_poolGroupOptions.PoolByIdentity) { // if we're pooling by identity (because integrated security is // being used for these connections) then we need to go out and // search for the connectionPool that matches the current identity. currentIdentity = DbConnectionPoolIdentity.GetCurrent(); // If the current token is restricted in some way, then we must // not attempt to pool these connections. if (currentIdentity.IsRestricted) { currentIdentity = null; } } if (null != currentIdentity) { if (!_poolCollection.TryGetValue(currentIdentity, out pool)) // find the pool { DbConnectionPoolProviderInfo connectionPoolProviderInfo = connectionFactory.CreateConnectionPoolProviderInfo(this.ConnectionOptions); // optimistically create pool, but its callbacks are delayed until after actual add DbConnectionPool newPool = new DbConnectionPool(connectionFactory, this, currentIdentity, connectionPoolProviderInfo); lock (this) { // Did someone already add it to the list? if (!_poolCollection.TryGetValue(currentIdentity, out pool)) { if (MarkPoolGroupAsActive()) { // If we get here, we know for certain that we there isn't // a pool that matches the current identity, so we have to // add the optimistically created one newPool.Startup(); // must start pool before usage bool addResult = _poolCollection.TryAdd(currentIdentity, newPool); Debug.Assert(addResult, "No other pool with current identity should exist at this point"); #if !MOBILE connectionFactory.PerformanceCounters.NumberOfActiveConnectionPools.Increment(); #endif pool = newPool; newPool = null; } else { // else pool entry has been disabled so don't create new pools Debug.Assert(PoolGroupStateDisabled == _state, "state should be disabled"); } } else { // else found an existing pool to use instead Debug.Assert(PoolGroupStateActive == _state, "state should be active since a pool exists and lock holds"); } } if (null != newPool) { // don't need to call connectionFactory.QueuePoolForRelease(newPool) because // pool callbacks were delayed and no risk of connections being created newPool.Shutdown(); } } // the found pool could be in any state } } if (null == pool) { lock (this) { // keep the pool entry state active when not pooling MarkPoolGroupAsActive(); } } return(pool); }
internal static DbConnectionPoolIdentity GetCurrent() { if (!ADP.IsWindowsNT) { return(NoIdentity); } WindowsIdentity currentWindowsIdentity = GetCurrentWindowsIdentity(); IntPtr windowsIdentityToken = GetWindowsIdentityToken(currentWindowsIdentity); uint tokenInformationLength = 0x800; uint tokenString = 0; IntPtr zero = IntPtr.Zero; IntPtr stringSid = IntPtr.Zero; System.Data.Common.UnsafeNativeMethods.SetLastError(0); bool isRestricted = System.Data.Common.UnsafeNativeMethods.IsTokenRestricted(windowsIdentityToken); if (Marshal.GetLastWin32Error() != 0) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } DbConnectionPoolIdentity identity = null; RuntimeHelpers.PrepareConstrainedRegions(); try { bool flag; if (!System.Data.Common.UnsafeNativeMethods.CheckTokenMembership(windowsIdentityToken, NetworkSid, out flag)) { IntegratedSecurityError(1); } RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { zero = SafeNativeMethods.LocalAlloc(0, (IntPtr)tokenInformationLength); } if (IntPtr.Zero == zero) { throw new OutOfMemoryException(); } if (!System.Data.Common.UnsafeNativeMethods.GetTokenInformation(windowsIdentityToken, 1, zero, tokenInformationLength, ref tokenString)) { if (tokenString > tokenInformationLength) { tokenInformationLength = tokenString; RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { SafeNativeMethods.LocalFree(zero); zero = IntPtr.Zero; zero = SafeNativeMethods.LocalAlloc(0, (IntPtr)tokenInformationLength); } if (IntPtr.Zero == zero) { throw new OutOfMemoryException(); } if (!System.Data.Common.UnsafeNativeMethods.GetTokenInformation(windowsIdentityToken, 1, zero, tokenInformationLength, ref tokenString)) { IntegratedSecurityError(2); } } else { IntegratedSecurityError(3); } } currentWindowsIdentity.Dispose(); if (!System.Data.Common.UnsafeNativeMethods.ConvertSidToStringSidW(Marshal.ReadIntPtr(zero, 0), out stringSid)) { IntegratedSecurityError(4); } if (IntPtr.Zero == stringSid) { throw ADP.InternalError(ADP.InternalErrorCode.ConvertSidToStringSidWReturnedNull); } identity = new DbConnectionPoolIdentity(Marshal.PtrToStringUni(stringSid), isRestricted, flag); } finally { if (IntPtr.Zero != zero) { SafeNativeMethods.LocalFree(zero); zero = IntPtr.Zero; } if (IntPtr.Zero != stringSid) { SafeNativeMethods.LocalFree(stringSid); stringSid = IntPtr.Zero; } } return(identity); }
private bool Start(string connectionString, out string server, out DbConnectionPoolIdentity identity, out string user, out string database, ref string queueService, string appDomainKey, SqlDependencyPerAppDomainDispatcher dispatcher, out bool errorOccurred, out bool appDomainStart, bool useDefaults) { bool flag2; IntPtr ptr; Bid.NotificationsScopeEnter(out ptr, "<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, queue: '%ls', appDomainKey: '%ls', perAppDomainDispatcher ID: '%d'", this.ObjectID, queueService, appDomainKey, dispatcher.ObjectID); try { server = null; identity = null; user = null; database = null; errorOccurred = false; appDomainStart = false; lock (this._sqlDependencyPerAppDomainDispatchers) { if (!this._sqlDependencyPerAppDomainDispatchers.ContainsKey(appDomainKey)) { this._sqlDependencyPerAppDomainDispatchers[appDomainKey] = dispatcher; } } SqlConnectionStringBuilder connectionStringBuilder = null; SqlConnectionContainerHashHelper key = GetHashHelper(connectionString, out connectionStringBuilder, out identity, out user, queueService); bool flag = false; SqlConnectionContainer container = null; lock (this._connectionContainers) { if (!this._connectionContainers.ContainsKey(key)) { Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, hashtable miss, creating new container.\n", this.ObjectID); container = new SqlConnectionContainer(key, appDomainKey, useDefaults); this._connectionContainers.Add(key, container); flag = true; appDomainStart = true; } else { container = this._connectionContainers[key]; Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, hashtable hit, container: %d\n", this.ObjectID, container.ObjectID); if (container.InErrorState) { Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, container: %d is in error state!\n", this.ObjectID, container.ObjectID); errorOccurred = true; } else { container.IncrementStartCount(appDomainKey, out appDomainStart); } } } if (useDefaults && !errorOccurred) { server = container.Server; database = container.Database; queueService = container.Queue; Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, default service: '%ls', server: '%ls', database: '%ls'\n", this.ObjectID, queueService, server, database); } Bid.NotificationsTrace("<sc.SqlDependencyProcessDispatcher.Start|DEP> %d#, started: %d\n", this.ObjectID, flag); flag2 = flag; } finally { Bid.ScopeLeave(ref ptr); } return flag2; }
private void PoolCreateRequest(object?state) { // called by pooler to ensure pool requests are currently being satisfied - // creation mutex has not been obtained if (State.Running == _state) { // in case WaitForPendingOpen ever failed with no subsequent OpenAsync calls, // start it back up again if (!_pendingOpens.IsEmpty && _pendingOpensWaiting == 0) { Thread waitOpenThread = new Thread(WaitForPendingOpen); waitOpenThread.IsBackground = true; waitOpenThread.Start(); } // Before creating any new objects, reclaim any released objects that were // not closed. ReclaimEmancipatedObjects(); if (!ErrorOccurred) { if (NeedToReplenish) { // Check to see if pool was created using integrated security and if so, make // sure the identity of current user matches that of user that created pool. // If it doesn't match, do not create any objects on the ThreadPool thread, // since either Open will fail or we will open a object for this pool that does // not belong in this pool. The side effect of this is that if using integrated // security min pool size cannot be guaranteed. if (UsingIntegrateSecurity && !_identity !.Equals(DbConnectionPoolIdentity.GetCurrent())) { return; } int waitResult = BOGUS_HANDLE; try { try { } finally { waitResult = WaitHandle.WaitAny(_waitHandles.GetHandles(withCreate: true), CreationTimeout); } if (CREATION_HANDLE == waitResult) { DbConnectionInternal newObj; // Check ErrorOccurred again after obtaining mutex if (!ErrorOccurred) { while (NeedToReplenish) { // Don't specify any user options because there is no outer connection associated with the new connection newObj = CreateObject(owningObject: null, userOptions: null, oldConnection: null); // We do not need to check error flag here, since we know if // CreateObject returned null, we are in error case. if (null != newObj) { PutNewObject(newObj); } else { break; } } } } else if (WaitHandle.WaitTimeout == waitResult) { // do not wait forever and potential block this worker thread // instead wait for a period of time and just requeue to try again QueuePoolCreateRequest(); } } finally { if (CREATION_HANDLE == waitResult) { // reuse waitResult and ignore its value _waitHandles.CreationSemaphore.Release(1); } } } } } }