Пример #1
0
        private PooledStream Create(CreateConnectionDelegate createConnectionCallback)
        {
            PooledStream stream = null;

            try
            {
                stream = createConnectionCallback(this);
                if (stream == null)
                {
                    throw new InternalException();
                }
                if (!stream.CanBePooled)
                {
                    throw new InternalException();
                }
                stream.PrePush(null);
                lock (this.m_ObjectList.SyncRoot)
                {
                    this.m_ObjectList.Add(stream);
                    this.m_TotalObjects = this.m_ObjectList.Count;
                }
            }
            catch (Exception exception)
            {
                stream          = null;
                this.m_ResError = exception;
                this.Abort();
            }
            return(stream);
        }
Пример #2
0
        /// <devdoc>
        ///    <para>Creates a new PooledStream is allowable</para>
        /// </devdoc>
        private PooledStream UserCreateRequest()
        {
            // called by user when they were not able to obtain a free object but
            // instead obtained creation mutex
            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::UserCreateRequest");

            PooledStream pooledStream = null;

            if (!ErrorOccurred)
            {
                if (Count < MaxPoolSize || 0 == MaxPoolSize)
                {
                    // If we have an odd number of total objects, reclaim any dead objects.
                    // If we did not find any objects to reclaim, create a new one.

                    //
                    if ((Count & 0x1) == 0x1 || !ReclaimEmancipatedObjects())
                    {
                        pooledStream = Create(m_CreateConnectionCallback);
                    }
                }
            }
            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::UserCreateRequest", ValidationHelper.HashString(pooledStream));
            return(pooledStream);
        }
Пример #3
0
        internal PooledStream GetConnection(object owningObject, GeneralAsyncDelegate asyncCallback, int creationTimeout)
        {
            int          num;
            PooledStream pooledStream = null;
            bool         continueLoop = true;
            bool         flag2        = asyncCallback != null;

            if (this.m_State != State.Running)
            {
                throw new InternalException();
            }
            Interlocked.Increment(ref this.m_WaitCount);
            WaitHandle[] waitHandles = this.m_WaitHandles;
            if (!flag2)
            {
                while ((pooledStream == null) && continueLoop)
                {
                    num          = WaitHandle.WaitAny(waitHandles, creationTimeout, false);
                    pooledStream = this.Get(owningObject, num, ref continueLoop, ref waitHandles);
                }
            }
            else
            {
                num = WaitHandle.WaitAny(waitHandles, 0, false);
                if (num != 0x102)
                {
                    pooledStream = this.Get(owningObject, num, ref continueLoop, ref waitHandles);
                }
                if (pooledStream == null)
                {
                    AsyncConnectionPoolRequest asyncRequest = new AsyncConnectionPoolRequest(this, owningObject, asyncCallback, creationTimeout);
                    this.QueueRequest(asyncRequest);
                }
            }
            if (pooledStream != null)
            {
                if (!pooledStream.IsInitalizing)
                {
                    asyncCallback = null;
                }
                try
                {
                    if (!pooledStream.Activate(owningObject, asyncCallback))
                    {
                        pooledStream = null;
                    }
                    return(pooledStream);
                }
                catch
                {
                    this.PutConnection(pooledStream, owningObject, creationTimeout, false);
                    throw;
                }
            }
            if (!flag2)
            {
                throw new InternalException();
            }
            return(pooledStream);
        }
Пример #4
0
 private void CleanupCallback()
 {
     while (this.Count > this.MinPoolSize)
     {
         if (this.Semaphore.WaitOne(0, false))
         {
             PooledStream pooledStream = (PooledStream)this.m_StackOld.Pop();
             if (pooledStream != null)
             {
                 this.Destroy(pooledStream);
                 continue;
             }
             this.Semaphore.ReleaseSemaphore();
         }
         break;
     }
     if (this.Semaphore.WaitOne(0, false))
     {
         while (true)
         {
             PooledStream stream2 = (PooledStream)this.m_StackNew.Pop();
             if (stream2 == null)
             {
                 break;
             }
             this.m_StackOld.Push(stream2);
         }
         this.Semaphore.ReleaseSemaphore();
     }
 }
Пример #5
0
        /// <devdoc>
        ///    <para>
        ///    Attempts to return a PooledStream to the pool.  If canReuse is false, then the
        ///    connection will be destroyed even if it is marked as reusable and a new conneciton will
        ///    be created.  If it is true, then the connection will still be checked to ensure that
        ///    it can be pooled and will be cleaned up if it can not for another reason.
        ///    </para>
        /// </devdoc>
        internal void PutConnection(PooledStream pooledStream, object owningObject, int creationTimeout, bool canReuse)
        {
            GlobalLog.Print("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutConnection");
            if (pooledStream == null)
            {
                throw new ArgumentNullException("pooledStream");
            }

            pooledStream.PrePush(owningObject);

            if (m_State != State.ShuttingDown)
            {
                pooledStream.Deactivate();

                // cancel our error status, if we have no new requests waiting anymore
                if (m_WaitCount == 0)
                {
                    CancelErrorCallback();
                }

                if (canReuse && pooledStream.CanBePooled)
                {
                    PutNew(pooledStream);
                }
                else
                {
                    try {
                        Destroy(pooledStream);
                    } finally { // Make sure to release the mutex even under error conditions.
                        // Make sure we recreate a new pooled stream, if there are requests for a stream
                        // at this point
                        if (m_WaitCount > 0)
                        {
                            if (!CreationMutex.WaitOne(creationTimeout, false))
                            {
                                Abort();
                            }
                            else
                            {
                                try {
                                    pooledStream = UserCreateRequest();
                                    if (null != pooledStream)
                                    {
                                        PutNew(pooledStream);
                                    }
                                } finally {
                                    CreationMutex.ReleaseMutex();
                                }
                            }
                        }
                    }
                }
            }
            else
            {
                // If we're shutting down, we destroy the object.
                Destroy(pooledStream);
            }
        }
 internal ConnectSocketState(ServicePoint servicePoint, PooledStream pooledStream, object owner, Socket s4, Socket s6)
 {
     this.servicePoint = servicePoint;
     this.pooledStream = pooledStream;
     this.owner        = owner;
     this.s4           = s4;
     this.s6           = s6;
 }
Пример #7
0
        private PooledStream Get(object owningObject, int result, ref bool continueLoop, ref WaitHandle[] waitHandles)
        {
            PooledStream fromPool = null;
            int          num2     = result;

            switch (num2)
            {
            case 1:
            {
                int num = Interlocked.Decrement(ref this.m_WaitCount);
                continueLoop = false;
                Exception resError = this.m_ResError;
                if (num == 0)
                {
                    this.CancelErrorCallback();
                }
                throw resError;
            }

            case 2:
                try
                {
                    continueLoop = true;
                    fromPool     = this.UserCreateRequest();
                    if (fromPool != null)
                    {
                        fromPool.PostPop(owningObject);
                        Interlocked.Decrement(ref this.m_WaitCount);
                        continueLoop = false;
                        return(fromPool);
                    }
                    if (((this.Count >= this.MaxPoolSize) && (this.MaxPoolSize != 0)) && !this.ReclaimEmancipatedObjects())
                    {
                        waitHandles = new WaitHandle[] { this.m_WaitHandles[0], this.m_WaitHandles[1] };
                    }
                    return(fromPool);
                }
                finally
                {
                    this.CreationMutex.ReleaseMutex();
                }
                break;

            default:
                if (num2 == 0x102)
                {
                    Interlocked.Decrement(ref this.m_WaitCount);
                    continueLoop = false;
                    throw new WebException(NetRes.GetWebStatusString("net_timeout", WebExceptionStatus.ConnectFailure), WebExceptionStatus.Timeout);
                }
                break;
            }
            Interlocked.Decrement(ref this.m_WaitCount);
            fromPool     = this.GetFromPool(owningObject);
            continueLoop = false;
            return(fromPool);
        }
        /// <devdoc>
        ///    <para>Places a new/reusable stream in the new stack of the pool</para>
        /// </devdoc>
        private void PutNew(PooledStream pooledStream)
        {
            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew", "#" + ValidationHelper.HashString(pooledStream));

            GlobalLog.Assert(null != pooledStream, "Why are we adding a null object to the pool?");
            GlobalLog.Assert(pooledStream.CanBePooled, "Non-poolable object in pool.");

            m_StackNew.Push(pooledStream);
            Semaphore.ReleaseSemaphore();
            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew");
        }
Пример #9
0
        /// <devdoc>
        ///    <para>Places a new/reusable stream in the new stack of the pool</para>
        /// </devdoc>
        private void PutNew(PooledStream pooledStream)
        {
            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew", "#" + ValidationHelper.HashString(pooledStream));

            GlobalLog.Assert(null != pooledStream, "Why are we adding a null object to the pool?");
            GlobalLog.Assert(pooledStream.CanBePooled, "Non-poolable object in pool.");

            m_StackNew.Push(pooledStream);
            // ensure that the semaphore's count is incremented to signal an available connection is in
            // the pool
            Semaphore.ReleaseSemaphore();
            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew");
        }
Пример #10
0
 internal void PutConnection(PooledStream pooledStream, object owningObject, int creationTimeout, bool canReuse)
 {
     if (pooledStream == null)
     {
         throw new ArgumentNullException("pooledStream");
     }
     pooledStream.PrePush(owningObject);
     if (this.m_State != State.ShuttingDown)
     {
         pooledStream.Deactivate();
         if (this.m_WaitCount == 0)
         {
             this.CancelErrorCallback();
         }
         if (canReuse && pooledStream.CanBePooled)
         {
             this.PutNew(pooledStream);
         }
         else
         {
             this.Destroy(pooledStream);
             if (this.m_WaitCount > 0)
             {
                 if (!this.CreationMutex.WaitOne(creationTimeout, false))
                 {
                     this.Abort();
                 }
                 else
                 {
                     try
                     {
                         pooledStream = this.UserCreateRequest();
                         if (pooledStream != null)
                         {
                             this.PutNew(pooledStream);
                         }
                     }
                     finally
                     {
                         this.CreationMutex.ReleaseMutex();
                     }
                 }
             }
         }
     }
     else
     {
         this.Destroy(pooledStream);
     }
 }
Пример #11
0
        private PooledStream UserCreateRequest()
        {
            PooledStream stream = null;

            if (this.ErrorOccurred || ((this.Count >= this.MaxPoolSize) && (this.MaxPoolSize != 0)))
            {
                return(stream);
            }
            if (((this.Count & 1) != 1) && this.ReclaimEmancipatedObjects())
            {
                return(stream);
            }
            return(this.Create(this.m_CreateConnectionCallback));
        }
        /// <summary>
        ///    <para>Processes async queued requests that are blocked on needing a free pooled stream
        ///         works as follows:
        ///         1. while there are blocked requests, take one out of the queue
        ///         2. Wait for a free connection, when one becomes avail, then notify the request that its there
        ///         3. repeat 1 until there are no more queued requests
        ///         4. if there are no more requests waiting to for a free stream, then close down this thread
        ///</para>
        /// </summary>
        private void AsyncThread()
        {
            do
            {
                while (m_QueuedRequests.Count > 0)
                {
                    bool continueLoop = true;
                    AsyncConnectionPoolRequest asyncState = null;
                    lock (m_QueuedRequests) {
                        asyncState = (AsyncConnectionPoolRequest)m_QueuedRequests.Dequeue();
                    }

                    WaitHandle [] localWaitHandles = m_WaitHandles;
                    PooledStream  PooledStream     = null;
                    try {
                        while ((PooledStream == null) && continueLoop)
                        {
                            int result = WaitHandle.WaitAny(localWaitHandles, asyncState.CreationTimeout, false);
                            PooledStream =
                                Get(asyncState.OwningObject, result, ref continueLoop, ref localWaitHandles);
                        }

                        PooledStream.Activate(asyncState.OwningObject, asyncState.AsyncCallback);
                    } catch (Exception e) {
                        if (PooledStream != null)
                        {
                            PooledStream.Close();
                            PutConnection(PooledStream, asyncState.OwningObject, asyncState.CreationTimeout);
                        }
                        asyncState.AsyncCallback(asyncState.OwningObject, e);
                    } catch {
                        if (PooledStream != null)
                        {
                            PooledStream.Close();
                            PutConnection(PooledStream, asyncState.OwningObject, asyncState.CreationTimeout);
                        }
                        asyncState.AsyncCallback(asyncState.OwningObject, new Exception(SR.GetString(SR.net_nonClsCompliantException)));
                    }
                }
                Thread.Sleep(500);
                lock (m_QueuedRequests) {
                    if (m_QueuedRequests.Count == 0)
                    {
                        m_AsyncThread = null;
                        break;
                    }
                }
            } while (true);
        }
Пример #13
0
        private PooledStream GetFromPool(object owningObject)
        {
            PooledStream stream = null;

            stream = (PooledStream)this.m_StackNew.Pop();
            if (stream == null)
            {
                stream = (PooledStream)this.m_StackOld.Pop();
            }
            if (stream != null)
            {
                stream.PostPop(owningObject);
            }
            return(stream);
        }
Пример #14
0
        private void AsyncThread()
        {
Label_00B1:
            while (this.m_QueuedRequests.Count > 0)
            {
                bool continueLoop = true;
                AsyncConnectionPoolRequest request = null;
                lock (this.m_QueuedRequests)
                {
                    request = (AsyncConnectionPoolRequest)this.m_QueuedRequests.Dequeue();
                }
                WaitHandle[] waitHandles  = this.m_WaitHandles;
                PooledStream pooledStream = null;
                try
                {
                    while ((pooledStream == null) && continueLoop)
                    {
                        int result = WaitHandle.WaitAny(waitHandles, request.CreationTimeout, false);
                        pooledStream = this.Get(request.OwningObject, result, ref continueLoop, ref waitHandles);
                    }
                    pooledStream.Activate(request.OwningObject, request.AsyncCallback);
                    continue;
                }
                catch (Exception exception)
                {
                    if (pooledStream != null)
                    {
                        this.PutConnection(pooledStream, request.OwningObject, request.CreationTimeout, false);
                    }
                    request.AsyncCallback(request.OwningObject, exception);
                    continue;
                }
            }
            Thread.Sleep(500);
            lock (this.m_QueuedRequests)
            {
                if (this.m_QueuedRequests.Count == 0)
                {
                    this.m_AsyncThread = null;
                }
                else
                {
                    goto Label_00B1;
                }
            }
        }
Пример #15
0
 private void Destroy(PooledStream pooledStream)
 {
     if (pooledStream != null)
     {
         try
         {
             lock (this.m_ObjectList.SyncRoot)
             {
                 this.m_ObjectList.Remove(pooledStream);
                 this.m_TotalObjects = this.m_ObjectList.Count;
             }
         }
         finally
         {
             pooledStream.Dispose();
         }
     }
 }
        /// <devdoc>
        ///    <para>Reclaim any pooled Streams that have seen their users/WebRequests GCed away</para>
        /// </devdoc>
        private bool ReclaimEmancipatedObjects()
        {
            bool emancipatedObjectFound = false;

            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::ReclaimEmancipatedObjects");

            lock (m_ObjectList.SyncRoot) {
                object[] objectList = m_ObjectList.ToArray();
                if (null != objectList)
                {
                    for (int i = 0; i < objectList.Length; ++i)
                    {
                        PooledStream pooledStream = (PooledStream)objectList[i];

                        if (null != pooledStream)
                        {
                            bool locked = false;

                            try {
                                locked = Monitor.TryEnter(pooledStream);

                                if (locked)
                                {
                                    if (pooledStream.IsEmancipated)
                                    {
                                        GlobalLog.Print("EmancipatedObject pooledStream#" + ValidationHelper.HashString(pooledStream));
                                        PutConnection(pooledStream, null, Timeout.Infinite);
                                        emancipatedObjectFound = true;
                                    }
                                }
                            }
                            finally {
                                if (locked)
                                {
                                    Monitor.Exit(pooledStream);
                                }
                            }
                        }
                    }
                }
            }
            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::ReclaimEmancipatedObjects", emancipatedObjectFound.ToString());
            return(emancipatedObjectFound);
        }
        /// <summary>
        ///    <para>Creates a new PooledStream, performs checks as well on the new stream</para>
        /// </summary>
        private PooledStream Create(CreateConnectionDelegate createConnectionCallback)
        {
            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::Create");
            PooledStream newObj = null;

            try {
                newObj = createConnectionCallback(this);

                if (null == newObj)
                {
                    throw new InternalException();    // Create succeeded, but null object
                }
                if (!newObj.CanBePooled)
                {
                    throw new InternalException();    // Create succeeded, but non-poolable object
                }
                newObj.PrePush(null);

                lock (m_ObjectList.SyncRoot) {
                    m_ObjectList.Add(newObj);
                    m_TotalObjects = m_ObjectList.Count;
                }

                GlobalLog.Print("Create pooledStream#" + ValidationHelper.HashString(newObj));
            }
            catch (Exception e)  {
                GlobalLog.Print("Pool Exception: " + e.Message);

                newObj = null; // set to null, so we do not return bad new object
                // Failed to create instance
                m_ResError = e;
                Abort();
            }
            catch {
                GlobalLog.Print("Pool Exception: Non-CLS Compliant Exception");

                newObj = null; // set to null, so we do not return bad new object
                // Failed to create instance
                m_ResError = new Exception(SR.GetString(SR.net_nonClsCompliantException));
                Abort();
            }
            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::Create", ValidationHelper.HashString(newObj));
            return(newObj);
        }
Пример #18
0
        /// <summary>
        /// Cleans up everything in both the old and new stack.  If a connection is in use
        /// then it will be on neither stack and it is the responsibility of the object
        /// using that connection to clean it up when it is finished using it.  This does
        /// not clean up the ConnectionPool object and new connections can still be
        /// created if needed in the future should this ConnectionPool object be reused
        ///
        /// preconditions: none
        ///
        /// postconditions: any connections not currently in use by an object will be
        /// gracefully terminated and purged from this connection pool
        /// </summary>
        internal void ForceCleanup()
        {
            if (Logging.On)
            {
                Logging.Enter(Logging.Web, "ConnectionPool::ForceCleanup");
            }

            // If WaitOne returns false, all connections in the pool are in use
            // so no cleanup should be performed. The last object owning
            // a connection from the pool will perform final cleanup.
            while (Count > 0)
            {
                if (Semaphore.WaitOne(0, false))
                {
                    // Try to clean up from new stack first, if there isn't anything on new
                    // then try old.  When we lock the Semaphore, it gives us a license to
                    // remove only one connection from the pool but it can be from either
                    // stack since if the Semaphore is locked by another thread it means that
                    // there must have been more than one connection available in either stack
                    PooledStream pooledStream = (PooledStream)m_StackNew.Pop();

                    // no streams in stack new, there must therefore be one in stack old since we
                    // were able to acquire the semaphore
                    if (pooledStream == null)
                    {
                        pooledStream = (PooledStream)m_StackOld.Pop();
                    }

                    Debug.Assert(pooledStream != null, "Acquired Semaphore with no connections in either stack");
                    Destroy(pooledStream);
                }
                else
                {
                    // couldn't get semaphore, nothing to do here
                    break;
                }
            }

            if (Logging.On)
            {
                Logging.Exit(Logging.Web, "ConnectionPool::ForceCleanup");
            }
        }
        /// <summary>
        ///    <para>Destroys a pooled stream from the pool</para>
        /// </summary>
        private void Destroy(PooledStream pooledStream)
        {
            GlobalLog.Print("Destroy pooledStream#" + ValidationHelper.HashString(pooledStream));

            try
            {
                lock (m_ObjectList.SyncRoot) {
                    m_ObjectList.Remove(pooledStream);
                    m_TotalObjects = m_ObjectList.Count;
                }
            }
            finally
            {
                if (null != pooledStream)
                {
                    pooledStream.Destroy();
                }
            }
        }
        internal Socket GetConnection(PooledStream PooledStream, object owner, bool async, out IPAddress address, ref Socket abortSocket, ref Socket abortSocket6, int timeout)
        {
            Socket             socket         = null;
            Socket             socket2        = null;
            Socket             socket3        = null;
            Exception          exception      = null;
            WebExceptionStatus connectFailure = WebExceptionStatus.ConnectFailure;

            address = null;
            if (Socket.OSSupportsIPv4)
            {
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }
            if (Socket.OSSupportsIPv6)
            {
                socket2 = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
            }
            abortSocket  = socket;
            abortSocket6 = socket2;
            ConnectSocketState state = null;

            if (async)
            {
                state = new ConnectSocketState(this, PooledStream, owner, socket, socket2);
            }
            connectFailure = this.ConnectSocket(socket, socket2, ref socket3, ref address, state, timeout, out exception);
            if (connectFailure == WebExceptionStatus.Pending)
            {
                return(null);
            }
            if (connectFailure != WebExceptionStatus.Success)
            {
                throw new WebException(NetRes.GetWebStatusString(connectFailure), ((connectFailure == WebExceptionStatus.ProxyNameResolutionFailure) || (connectFailure == WebExceptionStatus.NameResolutionFailure)) ? this.Host : null, exception, connectFailure, null, WebExceptionInternalStatus.ServicePointFatal);
            }
            if (socket3 == null)
            {
                throw new IOException(SR.GetString("net_io_transportfailure"));
            }
            this.CompleteGetConnection(socket, socket2, socket3, address);
            return(socket3);
        }
Пример #21
0
        private bool ReclaimEmancipatedObjects()
        {
            bool flag = false;

            lock (this.m_ObjectList.SyncRoot)
            {
                object[] objArray = this.m_ObjectList.ToArray();
                if (objArray == null)
                {
                    return(flag);
                }
                for (int i = 0; i < objArray.Length; i++)
                {
                    PooledStream stream = (PooledStream)objArray[i];
                    if (stream != null)
                    {
                        bool lockTaken = false;
                        try
                        {
                            Monitor.TryEnter(stream, ref lockTaken);
                            if (lockTaken && stream.IsEmancipated)
                            {
                                this.PutConnection(stream, null, -1);
                                flag = true;
                            }
                        }
                        finally
                        {
                            if (lockTaken)
                            {
                                Monitor.Exit(stream);
                            }
                        }
                    }
                }
            }
            return(flag);
        }
        /// <summary>
        ///    <para>Retrieves a pooled stream from the pool proper
        ///     this work by first attemting to find something in the pool on the New stack
        ///     and then trying the Old stack if something is not there availble </para>
        /// </summary>
        private PooledStream GetFromPool(object owningObject)
        {
            PooledStream res = null;

            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetFromPool");
            res = (PooledStream)m_StackNew.Pop();
            if (null == res)
            {
                res = (PooledStream)m_StackOld.Pop();
            }

            // Shouldn't be null, we could assert here.
            GlobalLog.Assert(res != null, "GetFromPool called with nothing in the pool!");

            if (null != res)
            {
                res.PostPop(owningObject);
                GlobalLog.Print("GetFromGeneralPool pooledStream#" + ValidationHelper.HashString(res));
            }

            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetFromPool", ValidationHelper.HashString(res));
            return(res);
        }
Пример #23
0
        /// <summary>
        ///    <para>Retrieves a pooled stream from the pool proper
        ///     this work by first attemting to find something in the pool on the New stack
        ///     and then trying the Old stack if something is not there availble </para>
        /// </summary>
        private PooledStream GetFromPool(object owningObject)
        {
            PooledStream res = null;

            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetFromPool");
            res = (PooledStream)m_StackNew.Pop();
            if (null == res)
            {
                res = (PooledStream)m_StackOld.Pop();
            }

            // The semaphore guaranteed that a connection was available so if res is
            // null it means that this contract has been violated somewhere
            GlobalLog.Assert(res != null, "GetFromPool called with nothing in the pool!");

            if (null != res)
            {
                res.PostPop(owningObject);
                GlobalLog.Print("GetFromGeneralPool pooledStream#" + ValidationHelper.HashString(res));
            }

            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetFromPool", ValidationHelper.HashString(res));
            return(res);
        }
Пример #24
0
 internal void ForceCleanup()
 {
     if (Logging.On)
     {
         Logging.Enter(Logging.Web, "ConnectionPool::ForceCleanup");
     }
     while (this.Count > 0)
     {
         if (!this.Semaphore.WaitOne(0, false))
         {
             break;
         }
         PooledStream pooledStream = (PooledStream)this.m_StackNew.Pop();
         if (pooledStream == null)
         {
             pooledStream = (PooledStream)this.m_StackOld.Pop();
         }
         this.Destroy(pooledStream);
     }
     if (Logging.On)
     {
         Logging.Exit(Logging.Web, "ConnectionPool::ForceCleanup");
     }
 }
 internal void PutConnection(PooledStream pooledStream, object owningObject, int creationTimeout, bool canReuse)
 {
     if (pooledStream == null)
     {
         throw new ArgumentNullException("pooledStream");
     }
     pooledStream.PrePush(owningObject);
     if (this.m_State != State.ShuttingDown)
     {
         pooledStream.Deactivate();
         if (this.m_WaitCount == 0)
         {
             this.CancelErrorCallback();
         }
         if (canReuse && pooledStream.CanBePooled)
         {
             this.PutNew(pooledStream);
         }
         else
         {
             this.Destroy(pooledStream);
             if (this.m_WaitCount > 0)
             {
                 if (!this.CreationMutex.WaitOne(creationTimeout, false))
                 {
                     this.Abort();
                 }
                 else
                 {
                     try
                     {
                         pooledStream = this.UserCreateRequest();
                         if (pooledStream != null)
                         {
                             this.PutNew(pooledStream);
                         }
                     }
                     finally
                     {
                         this.CreationMutex.ReleaseMutex();
                     }
                 }
             }
         }
     }
     else
     {
         this.Destroy(pooledStream);
     }
 }
Пример #26
0
 private void PutNew(PooledStream pooledStream)
 {
     this.m_StackNew.Push(pooledStream);
     this.Semaphore.ReleaseSemaphore();
 }
        /// <devdoc>
        ///    <para>Attempts to return a PooledStream to the pool</para>
        /// </devdoc>
        internal void PutConnection(PooledStream pooledStream, object owningObject, int creationTimeout) {
            GlobalLog.Print("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutConnection");
            if (pooledStream == null) {
                throw new ArgumentNullException("pooledStream");
            }

            pooledStream.PrePush(owningObject);

            if (m_State != State.ShuttingDown) {
                pooledStream.Deactivate();

                // cancel our error status, if we have no new requests waiting anymore
                if (m_WaitCount == 0) {
                    CancelErrorCallback();
                }

                if (pooledStream.CanBePooled) {
                    PutNew(pooledStream);
                }
                else {
                    Destroy(pooledStream);

                    // Make sure we recreate a new pooled stream, if there are requests for a stream
                    // at this point
                    if (m_WaitCount > 0) {
                        if (!CreationMutex.WaitOne(creationTimeout, false)) {
                            Abort();
                        } else {
                            try {
                                pooledStream = UserCreateRequest();
                                if (null != pooledStream) {
                                    PutNew(pooledStream);
                                }
                            } finally {
                                CreationMutex.ReleaseMutex();
                            }
                        }
                    }
                }
            }
            else {
                // If we're shutting down, we destroy the object.
                Destroy(pooledStream);
            }
        }
Пример #28
0
 internal void PutConnection(PooledStream pooledStream, object owningObject, int creationTimeout)
 {
     this.PutConnection(pooledStream, owningObject, creationTimeout, true);
 }
 private void PutNew(PooledStream pooledStream)
 {
     this.m_StackNew.Push(pooledStream);
     this.Semaphore.ReleaseSemaphore();
 }
 internal Socket GetConnection(PooledStream PooledStream, object owner, bool async, out IPAddress address, ref Socket abortSocket, ref Socket abortSocket6, int timeout)
 {
     Socket socket = null;
     Socket socket2 = null;
     Socket socket3 = null;
     Exception exception = null;
     WebExceptionStatus connectFailure = WebExceptionStatus.ConnectFailure;
     address = null;
     if (Socket.OSSupportsIPv4)
     {
         socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
     }
     if (Socket.OSSupportsIPv6)
     {
         socket2 = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
     }
     abortSocket = socket;
     abortSocket6 = socket2;
     ConnectSocketState state = null;
     if (async)
     {
         state = new ConnectSocketState(this, PooledStream, owner, socket, socket2);
     }
     connectFailure = this.ConnectSocket(socket, socket2, ref socket3, ref address, state, timeout, out exception);
     if (connectFailure == WebExceptionStatus.Pending)
     {
         return null;
     }
     if (connectFailure != WebExceptionStatus.Success)
     {
         throw new WebException(NetRes.GetWebStatusString(connectFailure), ((connectFailure == WebExceptionStatus.ProxyNameResolutionFailure) || (connectFailure == WebExceptionStatus.NameResolutionFailure)) ? this.Host : null, exception, connectFailure, null, WebExceptionInternalStatus.ServicePointFatal);
     }
     if (socket3 == null)
     {
         throw new IOException(SR.GetString("net_io_transportfailure"));
     }
     this.CompleteGetConnection(socket, socket2, socket3, address);
     return socket3;
 }
        /// <summary>
        ///    <para>This is called by a timer, to check for needed cleanup of idle pooled streams</para>
        /// </summary>
        private void CleanupCallback()
        {
            // Called when the cleanup-timer ticks over.
            //
            // This is the automatic prunning method.  Every period, we will perform a two-step
            // process.  First, for the objects above MinPool, we will obtain the semaphore for
            // the object and then destroy it if it was on the old stack.  We will continue this
            // until we either reach MinPool size, or we are unable to obtain a free object, or
            // until we have exhausted all the objects on the old stack.  After that, push all
            // objects on the new stack to the old stack.  So, every period the objects on the
            // old stack are destroyed and the objects on the new stack are pushed to the old
            // stack.  All objects that are currently out and in use are not on either stack.
            // With this logic, a object is prunned if unused for at least one period but not
            // more than two periods.

            // Destroy free objects above MinPool size from old stack.
            while (Count > MinPoolSize)  // While above MinPoolSize...

            {
                if (Semaphore.WaitOne(0, false))    // != WaitTimeout
                // We obtained a objects from the semaphore.
                {
                    PooledStream pooledStream = (PooledStream)m_StackOld.Pop();

                    if (null != pooledStream)
                    {
                        // If we obtained one from the old stack, destroy it.
                        Destroy(pooledStream);
                    }
                    else
                    {
                        // Else we exhausted the old stack, so break.
                        Semaphore.ReleaseSemaphore();
                        break;
                    }
                }
                else
                {
                    break;
                }
            }

            // Push to the old-stack.  For each free object, move object from new stack
            // to old stack.
            if (Semaphore.WaitOne(0, false))  //  != WaitTimeout
            {
                for (;;)
                {
                    PooledStream pooledStream = (PooledStream)m_StackNew.Pop();

                    if (null == pooledStream)
                    {
                        break;
                    }

                    GlobalLog.Assert(!pooledStream.IsEmancipated, "Pooled object not in pool.");
                    GlobalLog.Assert(pooledStream.CanBePooled, "Pooled object is not poolable.");

                    m_StackOld.Push(pooledStream);
                }
                Semaphore.ReleaseSemaphore();
            }
        }
 private void Destroy(PooledStream pooledStream)
 {
     if (pooledStream != null)
     {
         try
         {
             lock (this.m_ObjectList.SyncRoot)
             {
                 this.m_ObjectList.Remove(pooledStream);
                 this.m_TotalObjects = this.m_ObjectList.Count;
             }
         }
         finally
         {
             pooledStream.Dispose();
         }
     }
 }
 internal Socket GetConnection(PooledStream PooledStream, object owner, bool async, out IPAddress address, ref Socket abortSocket, ref Socket abortSocket6)
 {
     throw new NotImplementedException();
 }
        /// <devdoc>
        ///    <para>Attempts to create a PooledStream, by trying to get a pooled Connection,
        ///         or by creating its own new one</para>
        /// </devdoc>
        internal PooledStream GetConnection(object owningObject,
                                            GeneralAsyncDelegate asyncCallback,
                                            int creationTimeout)
        {
            int          result;
            PooledStream stream       = null;
            bool         continueLoop = true;
            bool         async        = (asyncCallback != null) ? true : false;

            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetConnection");

            if (m_State != State.Running)
            {
                throw new InternalException();
            }

            Interlocked.Increment(ref m_WaitCount);
            WaitHandle[] localWaitHandles = m_WaitHandles;

            if (async)
            {
                result = WaitHandle.WaitAny(localWaitHandles, 0, false);
                if (result != WaitTimeout)
                {
                    stream = Get(owningObject, result, ref continueLoop, ref localWaitHandles);
                }
                if (stream == null)
                {
                    GlobalLog.Print("GetConnection:" + ValidationHelper.HashString(this) + " going async");
                    AsyncConnectionPoolRequest asyncState = new AsyncConnectionPoolRequest(this, owningObject, asyncCallback, creationTimeout);
                    QueueRequest(asyncState);
                }
            }
            else
            {
                // loop while we don't have an error/timeout and we haven't gotten a stream yet
                while ((stream == null) && continueLoop)
                {
                    result = WaitHandle.WaitAny(localWaitHandles, creationTimeout, false);
                    stream = Get(owningObject, result, ref continueLoop, ref localWaitHandles);
                }
            }

            if (null != stream)
            {
                // if there is already a stream, then we're not going async
                if (!stream.IsInitalizing)
                {
                    asyncCallback = null;
                }

                try{
                    // If activate returns false, it is going to finish asynchronously
                    // and therefore the stream will be returned in a callback and
                    // we should not return it here (return null)
                    if (stream.Activate(owningObject, asyncCallback) == false)
                    {
                        stream = null;
                    }
                }
                catch {
                    stream.Close();
                    PutConnection(stream, owningObject, creationTimeout);
                    throw;
                }
            }
            else if (!async)
            {
                throw new InternalException();
            }

            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::GetConnection", ValidationHelper.HashString(stream));
            return(stream);
        }
Пример #35
0
 /// <devdoc>
 ///     <para>
 ///     Attempts to return a PooledStream to the pool.  Default is that it can be reused if it can 
 ///     also be pooled.
 ///     </para>
 /// </devdoc>
 internal void PutConnection(PooledStream pooledStream, object owningObject, int creationTimeout)
 {
     // ok to reuse
     PutConnection(pooledStream, owningObject, creationTimeout, true);
 }
Пример #36
0
        /// <devdoc>
        ///    <para>Places a new/reusable stream in the new stack of the pool</para>
        /// </devdoc>
        private void PutNew(PooledStream pooledStream) {
            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew", "#"+ValidationHelper.HashString(pooledStream));

            GlobalLog.Assert(null != pooledStream, "Why are we adding a null object to the pool?");
            GlobalLog.Assert(pooledStream.CanBePooled, "Non-poolable object in pool.");

            m_StackNew.Push(pooledStream);
            // ensure that the semaphore's count is incremented to signal an available connection is in
            // the pool
            Semaphore.ReleaseSemaphore();
            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew");
        }
 internal void GetConnection(ServicePoint servicePoint)
 {
     if (this.isConnected)
     {
         throw new InvalidOperationException(SR.GetString("SmtpAlreadyConnected"));
     }
     if (Logging.On)
     {
         Logging.Associate(Logging.Web, this, servicePoint);
     }
     this.connectionPool = ConnectionPoolManager.GetConnectionPool(servicePoint, "", m_CreateConnectionCallback);
     PooledStream pooledStream = this.connectionPool.GetConnection(this, null, this.Timeout);
     while ((((SmtpPooledStream) pooledStream).creds != null) && (((SmtpPooledStream) pooledStream).creds != this.credentials))
     {
         this.connectionPool.PutConnection(pooledStream, pooledStream.Owner, this.Timeout, false);
         pooledStream = this.connectionPool.GetConnection(this, null, this.Timeout);
     }
     if (Logging.On)
     {
         Logging.Associate(Logging.Web, this, pooledStream);
     }
     lock (this)
     {
         this.pooledStream = pooledStream;
     }
     ((SmtpPooledStream) pooledStream).creds = this.credentials;
     this.responseReader = new SmtpReplyReaderFactory(pooledStream.NetworkStream);
     pooledStream.UpdateLifetime();
     if (((SmtpPooledStream) pooledStream).previouslyUsed)
     {
         this.isConnected = true;
     }
     else
     {
         LineInfo info = this.responseReader.GetNextReplyReader().ReadLine();
         if (info.StatusCode != SmtpStatusCode.ServiceReady)
         {
             throw new SmtpException(info.StatusCode, info.Line, true);
         }
         try
         {
             this.extensions = EHelloCommand.Send(this, this.client.clientDomain);
             this.ParseExtensions(this.extensions);
         }
         catch (SmtpException exception)
         {
             if ((exception.StatusCode != SmtpStatusCode.CommandUnrecognized) && (exception.StatusCode != SmtpStatusCode.CommandNotImplemented))
             {
                 throw exception;
             }
             HelloCommand.Send(this, this.client.clientDomain);
             this.supportedAuth = SupportedAuth.Login;
         }
         if (this.enableSsl)
         {
             if (!this.serverSupportsStartTls && !(pooledStream.NetworkStream is TlsStream))
             {
                 throw new SmtpException(SR.GetString("MailServerDoesNotSupportStartTls"));
             }
             StartTlsCommand.Send(this);
             TlsStream stream2 = new TlsStream(servicePoint.Host, pooledStream.NetworkStream, this.clientCertificates, servicePoint, this.client, null);
             pooledStream.NetworkStream = stream2;
             this.channelBindingToken = stream2.GetChannelBinding(ChannelBindingKind.Unique);
             this.responseReader = new SmtpReplyReaderFactory(pooledStream.NetworkStream);
             this.extensions = EHelloCommand.Send(this, this.client.clientDomain);
             this.ParseExtensions(this.extensions);
         }
         if (this.credentials != null)
         {
             for (int i = 0; i < this.authenticationModules.Length; i++)
             {
                 Authorization authorization;
                 if (this.AuthSupported(this.authenticationModules[i]))
                 {
                     NetworkCredential credential = this.credentials.GetCredential(servicePoint.Host, servicePoint.Port, this.authenticationModules[i].AuthenticationType);
                     if (credential != null)
                     {
                         authorization = this.SetContextAndTryAuthenticate(this.authenticationModules[i], credential, null);
                         if ((authorization != null) && (authorization.Message != null))
                         {
                             info = AuthCommand.Send(this, this.authenticationModules[i].AuthenticationType, authorization.Message);
                             if (info.StatusCode != SmtpStatusCode.CommandParameterNotImplemented)
                             {
                                 goto Label_0363;
                             }
                         }
                     }
                 }
                 continue;
             Label_02F2:
                 authorization = this.authenticationModules[i].Authenticate(info.Line, null, this, this.client.TargetName, this.channelBindingToken);
                 if (authorization == null)
                 {
                     throw new SmtpException(SR.GetString("SmtpAuthenticationFailed"));
                 }
                 info = AuthCommand.Send(this, authorization.Message);
                 if (info.StatusCode == ((SmtpStatusCode) 0xeb))
                 {
                     this.authenticationModules[i].CloseContext(this);
                     this.isConnected = true;
                     return;
                 }
             Label_0363:
                 if (info.StatusCode == ((SmtpStatusCode) 0x14e))
                 {
                     goto Label_02F2;
                 }
             }
         }
         this.isConnected = true;
     }
 }
        /// <devdoc>
        ///    <para>Places a new/reusable stream in the new stack of the pool</para>
        /// </devdoc>
        private void PutNew(PooledStream pooledStream) {
            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew", "#"+ValidationHelper.HashString(pooledStream));

            GlobalLog.Assert(null != pooledStream, "Why are we adding a null object to the pool?");
            GlobalLog.Assert(pooledStream.CanBePooled, "Non-poolable object in pool.");

            m_StackNew.Push(pooledStream);
            Semaphore.ReleaseSemaphore();
            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::PutNew");
        }
        /// <devdoc>
        ///    <para>
        ///     Tempory for getting a new Connection for FTP client, for the time being
        ///    </para>
        /// </devdoc>
        internal Socket GetConnection(PooledStream PooledStream, object owner, bool async, out IPAddress address, ref Socket abortSocket, ref Socket abortSocket6)
        {
            Socket socket = null;
            Socket socket6 = null;
            Socket finalSocket = null;
            Exception innerException = null;
            WebExceptionStatus ws = WebExceptionStatus.ConnectFailure;
            address = null;

            //
            // if we will not create a tunnel through a proxy then create
            // and connect the socket we will use for the connection
            //

            //
            // IPv6 Support: If IPv6 is enabled, then we create a second socket that ServicePoint
            //               will use if it wants to connect via IPv6.
            //
            if ( Socket.OSSupportsIPv4 ) {
                socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
            }

            if ( Socket.OSSupportsIPv6 ) {
                socket6 = new Socket(AddressFamily.InterNetworkV6,SocketType.Stream,ProtocolType.Tcp);
            }

            abortSocket = socket;
            abortSocket6 = socket6;

            //
            // Setup socket timeouts for [....] requests
            //
            // 

            ConnectSocketState state = null;

            if (async) {
                state = new ConnectSocketState(this, PooledStream, owner, socket, socket6);
            }

            ws = ConnectSocket(socket, socket6, ref finalSocket, ref address, state, out innerException);

            if (ws == WebExceptionStatus.Pending) {
                return null;
            }

            if (ws != WebExceptionStatus.Success) {
                throw new WebException(
                    NetRes.GetWebStatusString(ws),
                    ws == WebExceptionStatus.ProxyNameResolutionFailure || ws == WebExceptionStatus.NameResolutionFailure ? Host : null,
                    innerException,
                    ws,
                    null, /* no response */
                    WebExceptionInternalStatus.ServicePointFatal);
            }

            //
            // There should be no means for socket to be null at this
            // point, but the damage is greater if we just carry on
            // without ensuring that it's good.
            //
            if ( finalSocket == null ) {
                throw new IOException(SR.GetString(SR.net_io_transportfailure));
            }

            CompleteGetConnection(socket, socket6, finalSocket, address);
            return finalSocket;
        }
        /// <summary>
        ///    <para>Retrieves the pooled stream out of the pool, does this by using the result
        ///    of a WaitAny as input, and then based on whether it has a mutex, event, semaphore,
        ///     or timeout decides what action to take</para>
        /// </summary>
        private PooledStream Get(object owningObject, int result, ref bool continueLoop, ref WaitHandle [] waitHandles)
        {
            PooledStream pooledStream = null;

            GlobalLog.Enter("ConnectionPool#" + ValidationHelper.HashString(this) + "::Get", result.ToString());


            // From the WaitAny docs: "If more than one object became signaled during
            // the call, this is the array index of the signaled object with the
            // smallest index value of all the signaled objects."  This is important
            // so that the free object signal will be returned before a creation
            // signal.

            switch (result)
            {
            case WaitTimeout:
                Interlocked.Decrement(ref m_WaitCount);
                continueLoop = false;
                GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::Get", "throw Timeout WebException");
                throw new WebException(NetRes.GetWebStatusString("net_timeout", WebExceptionStatus.ConnectFailure), WebExceptionStatus.Timeout);


            case ErrorHandleIndex:
                // Throw the error that PoolCreateRequest stashed.
                int newWaitCount = Interlocked.Decrement(ref m_WaitCount);
                continueLoop = false;
                Exception exceptionToThrow = m_ResError;
                if (newWaitCount == 0)
                {
                    CancelErrorCallback();
                }
                throw exceptionToThrow;

            case CreationHandleIndex:
                try {
                    continueLoop = true;
                    pooledStream = UserCreateRequest();

                    if (null != pooledStream)
                    {
                        pooledStream.PostPop(owningObject);
                        Interlocked.Decrement(ref m_WaitCount);
                        continueLoop = false;
                    }
                    else
                    {
                        // If we were not able to create an object, check to see if
                        // we reached MaxPoolSize.  If so, we will no longer wait on
                        // the CreationHandle, but instead wait for a free object or
                        // the timeout.

                        // BUG - if we receive the CreationHandle midway into the wait
                        // period and re-wait, we will be waiting on the full period
                        if (Count >= MaxPoolSize && 0 != MaxPoolSize)
                        {
                            if (!ReclaimEmancipatedObjects())
                            {
                                // modify handle array not to wait on creation mutex anymore
                                waitHandles    = new WaitHandle[2];
                                waitHandles[0] = m_WaitHandles[0];
                                waitHandles[1] = m_WaitHandles[1];
                            }
                        }
                    }
                }
                finally {
                    CreationMutex.ReleaseMutex();
                }
                break;

            default:
                //
                //    guaranteed available inventory
                //
                Interlocked.Decrement(ref m_WaitCount);
                pooledStream = GetFromPool(owningObject);
                continueLoop = false;
                break;
            }
            GlobalLog.Leave("ConnectionPool#" + ValidationHelper.HashString(this) + "::Get", ValidationHelper.HashString(pooledStream));
            return(pooledStream);
        }
 internal ConnectSocketState(ServicePoint servicePoint, PooledStream pooledStream, object owner, Socket s4, Socket s6)
 {
     this.servicePoint = servicePoint;
     this.pooledStream = pooledStream;
     this.owner = owner;
     this.s4 = s4;
     this.s6 = s6;
 }
Пример #42
0
        internal void GetConnection(ServicePoint servicePoint)
        {
            if (isConnected)
            {
                throw new InvalidOperationException(SR.GetString(SR.SmtpAlreadyConnected));
            }

            if (Logging.On) Logging.Associate(Logging.Web, this, servicePoint);
            Debug.Assert(servicePoint != null, "servicePoint was null from SmtpTransport");
            connectionPool = ConnectionPoolManager.GetConnectionPool(servicePoint, "", m_CreateConnectionCallback);

            PooledStream pooledStream = connectionPool.GetConnection((object)this, null, Timeout);

            while (((SmtpPooledStream)pooledStream).creds != null && ((SmtpPooledStream)pooledStream).creds != credentials) {
                // destroy this connection so that a new connection can be created 
                // in order to use the proper credentials.  Do not just close the 
                // connection since it's in a state where a QUIT could be sent
                connectionPool.PutConnection(pooledStream, pooledStream.Owner, Timeout, false);
                pooledStream = connectionPool.GetConnection((object)this, null, Timeout);
            }
            if (Logging.On) Logging.Associate(Logging.Web, this, pooledStream);

            lock (this) {
                this.pooledStream = pooledStream;
            }

            ((SmtpPooledStream)pooledStream).creds = credentials;

            responseReader = new SmtpReplyReaderFactory(pooledStream.NetworkStream);

            //set connectionlease
            pooledStream.UpdateLifetime();

            //if the stream was already used, then we've already done the handshake
            if (((SmtpPooledStream)pooledStream).previouslyUsed == true) {
                isConnected = true;
                return;
            }

            LineInfo info = responseReader.GetNextReplyReader().ReadLine();

            switch (info.StatusCode) 
            {
                case SmtpStatusCode.ServiceReady: 
                    {
                        break;
                    }
                default: 
                    {
                        throw new SmtpException(info.StatusCode, info.Line, true);
                    }
            }

            try
            {
                extensions = EHelloCommand.Send(this, client.clientDomain);
                ParseExtensions(extensions);
            }
            catch (SmtpException e)
            {
                if ((e.StatusCode != SmtpStatusCode.CommandUnrecognized)
                    && (e.StatusCode != SmtpStatusCode.CommandNotImplemented)) {
                    throw e;
                }

                HelloCommand.Send(this, client.clientDomain);
                //if ehello isn't supported, assume basic login
                supportedAuth = SupportedAuth.Login;
            }

#if !FEATURE_PAL
            // Establish TLS
            if (enableSsl) 
            {
                if (!serverSupportsStartTls) 
                {
                    // Either TLS is already established or server does not support TLS
                    if (!(pooledStream.NetworkStream is TlsStream)) 
                    {
                        throw new SmtpException(SR.GetString(SR.MailServerDoesNotSupportStartTls));
                    }
                }
                StartTlsCommand.Send(this);
                TlsStream TlsStream = new TlsStream(servicePoint.Host, pooledStream.NetworkStream, clientCertificates, servicePoint, client, null);

                pooledStream.NetworkStream = TlsStream;

                //for SMTP, the CBT should be unique
                this.channelBindingToken = TlsStream.GetChannelBinding(ChannelBindingKind.Unique);

                responseReader = new SmtpReplyReaderFactory(pooledStream.NetworkStream);

                // According to RFC 3207: The client SHOULD send an EHLO command 
                // as the first command after a successful TLS negotiation.
                extensions = EHelloCommand.Send(this, client.clientDomain);
                ParseExtensions(extensions);
            }
#endif // !FEATURE_PAL

            //if no credentials were supplied, try anonymous
            //servers don't appear to anounce that they support anonymous login.
            if (credentials != null) {

                for (int i = 0; i < authenticationModules.Length; i++) 
                {

                    //only authenticate if the auth protocol is supported  - [....]
                    if (!AuthSupported(authenticationModules[i])) {
                        continue;
                    }

                    NetworkCredential credential = credentials.GetCredential(servicePoint.Host, 
                        servicePoint.Port, authenticationModules[i].AuthenticationType);
                    if (credential == null)
                        continue;

                    Authorization auth = SetContextAndTryAuthenticate(authenticationModules[i], credential, null);

                    if (auth != null && auth.Message != null) 
                    {
                        info = AuthCommand.Send(this, authenticationModules[i].AuthenticationType, auth.Message);

                        if (info.StatusCode == SmtpStatusCode.CommandParameterNotImplemented) 
                        {
                            continue;
                        }

                        while ((int)info.StatusCode == 334) 
                        {
                            auth = authenticationModules[i].Authenticate(info.Line, null, this, this.client.TargetName, this.channelBindingToken);
                            if (auth == null)
                            {
                                throw new SmtpException(SR.GetString(SR.SmtpAuthenticationFailed));
                            }
                            info = AuthCommand.Send(this, auth.Message);

                            if ((int)info.StatusCode == 235)
                            {
                                authenticationModules[i].CloseContext(this);
                                isConnected = true;
                                return;
                            }
                        }
                    }
                }
            }
            isConnected = true;
        }
Пример #43
0
		internal Socket GetConnection(PooledStream PooledStream, object owner, bool async, out IPAddress address, ref Socket abortSocket, ref Socket abortSocket6)
		{
			throw new NotImplementedException ();
		}
        /// <summary>
        ///    <para>Destroys a pooled stream from the pool</para>
        /// </summary>
        private void Destroy(PooledStream pooledStream) {
            GlobalLog.Print("Destroy pooledStream#"+ValidationHelper.HashString(pooledStream));

            try
            {
                lock (m_ObjectList.SyncRoot) {
                    m_ObjectList.Remove(pooledStream);
                    m_TotalObjects = m_ObjectList.Count;
                }
            }
            finally
            {
                if (null != pooledStream) {
                    pooledStream.Destroy();
                }
            }
        }