Ejemplo n.º 1
0
        /*++

        Routine Description:

           BeginAccept - Does a async winsock accept, creating a new socket on success

            Works by creating a pending accept request the first time,
            and subsequent calls are queued so that when the first accept completes,
            the next accept can be resubmitted in the callback.
            this routine may go pending at which time,
            but any case the callback Delegate will be called upon completion

        Arguments:

           Callback - Async Callback Delegate that is called upon Async Completion
           State - State used to track callback, set by caller, not required

        Return Value:

           IAsyncResult - Async result used to retreive resultant new socket

        --*/

        /// <include file='doc\Socket.uex' path='docs/doc[@for="Socket.BeginAccept"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public IAsyncResult BeginAccept(AsyncCallback callback, object state) {
            if (CleanedUp) {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            if (m_RightEndPoint==null) {
                throw new InvalidOperationException(SR.GetString(SR.net_sockets_mustbind));
            }

            //
            // We keep a queue, which lists the set of requests that want to
            //  be called when an accept queue completes.  We call accept
            //  once, and then as it completes asyncrounsly we pull the
            //  requests out of the queue and call their callback.
            //
            // We start by grabbing Critical Section, then attempt to
            //  determine if we haven an empty Queue of Accept Sockets
            //  or if its in a Callback on the Callback thread.
            //
            // If its in the callback thread proocessing of the callback, then we
            //  just need to notify the callback by adding an additional request
            //   to the queue.
            //
            // If its an empty queue, and its not in the callback, then
            //   we just need to get the Accept going, make it go async
            //   and leave.
            //
            GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept()");

            AcceptAsyncResult asyncResult = new AcceptAsyncResult(this, state, callback);

            Monitor.Enter(this);

            if (AcceptQueue.Count==0 && !incallback) {
                //
                // if the accept queue is empty
                //
                AcceptQueue.Add(asyncResult);

                SocketAddress socketAddress = m_RightEndPoint.Serialize();

                // get async going
                SetAsyncEventSelect(AsyncEventBits.FdAccept);

                GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() queue is empty calling UnsafeNclNativeMethods.OSSOCK.accept");

                IntPtr acceptedSocketHandle =
                    UnsafeNclNativeMethods.OSSOCK.accept(
                        m_Handle,
                        socketAddress.m_Buffer,
                        ref socketAddress.m_Size );

                int errorCode = acceptedSocketHandle!=SocketErrors.InvalidSocketIntPtr ? 0 : Marshal.GetLastWin32Error();

                GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() UnsafeNclNativeMethods.OSSOCK.accept returns:" + errorCode.ToString());

                if (errorCode==SocketErrors.Success) {
                    asyncResult.Result = CreateAcceptSocket(acceptedSocketHandle, m_RightEndPoint.Create(socketAddress));
                }
                //
                // the following code will call Monitor.Exit(this) as soon as possible
                //
                asyncResult.CheckAsyncCallResult(errorCode);

                //
                // if the asynchronous native call fails synchronously
                // we'll throw a SocketException
                //
                if (asyncResult.ErrorCode!=SocketErrors.Success) {
                    //
                    // update our internal state after this socket error and throw
                    //
                    UpdateStatusAfterSocketError();
                    throw new SocketException(asyncResult.ErrorCode);
                }
            }
            else {
                AcceptQueue.Add(asyncResult);

                GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() queue is not empty Count:" + AcceptQueue.Count.ToString());

                Monitor.Exit(this);
            }

            GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginAccept() returning AsyncResult:" + ValidationHelper.HashString(asyncResult));

            return asyncResult;
        }