Example #1
0
        //
        // This method is called after an asynchronous call is made for the user,
        // it checks and acts accordingly if the IO:
        // 1) completed synchronously.
        // 2) was pended.
        // 3) failed.
        //
        internal void CheckAsyncCallResult(int status)
        {
            Socket socket = (Socket)AsyncObject;

            switch (status)
            {
            case SocketErrors.Success:
                //
                // the Async IO call completed synchronously:
                //
                break;

            case SocketErrors.WSAEWOULDBLOCK:
                //
                // the Async IO call was pended:
                // Queue our event to the thread pool.
                //
                GlobalLog.Assert(
                    socket.m_AsyncEvent != null,
                    "ConnectAsyncResult: m_AsyncConnectEvent == null", string.Empty);

                ThreadPool.RegisterWaitForSingleObject(
                    socket.m_AsyncEvent,
                    m_ConnectCallback,
                    this,
                    -1,
                    true);

                //
                // we're done, return
                //
                return;

            default:
                //
                // the Async IO call failed:
                // set the Result to the Win32 error
                //
                ErrorCode = status;
                break;
            }
            //
            // cancel async event
            //
            socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
            //
            // go back to blocking mode
            //
            socket.InternalSetBlocking(true);
            if (status == SocketErrors.Success)
            {
                //
                // synchronously complete the IO and call the user's callback.
                //
                InvokeCallback(true);
            }
        }
        //
        // This method is called after an asynchronous call is made for the user,
        // it checks and acts accordingly if the IO:
        // 1) completed synchronously.
        // 2) was pended.
        // 3) failed.
        //
        internal void CheckAsyncCallResult(int status)
        {
            Socket socket = (Socket)AsyncObject;

            GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::CheckAsyncCallResult() status:" + status.ToString());

            switch (status)
            {
            case SocketErrors.Success:
                //
                // the Async IO call completed synchronously:
                //
                break;

            case SocketErrors.WSAEWOULDBLOCK:
                //
                // the Async IO call was pended:
                // Queue our event to the thread pool.
                //
                Monitor.Exit(socket);

                GlobalLog.Assert(
                    socket.m_AsyncEvent != null,
                    "ConnectAsyncResult: m_AsyncAcceptEvent == null", string.Empty);

                ThreadPool.RegisterWaitForSingleObject(
                    socket.m_AsyncEvent,
                    m_AcceptCallback,
                    this,
                    -1,
                    true);

                //
                // we're done, return
                //
                return;

            default:
                //
                // the Async IO call failed:
                // set the Result to the Win32 error
                //
                ErrorCode = status;
                break;
            }
            //
            // dequeue from the accept list since the accept completed
            //
            socket.AcceptQueue.RemoveAt(socket.AcceptQueue.Count - 1);
            if (socket.AcceptQueue.Count == 0)
            {
                //
                // if the queue is now empty
                // cancel async event
                //
                socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
                //
                // go back to blocking mode
                //
                socket.InternalSetBlocking(true);
            }
            Monitor.Exit(socket);

            if (status == SocketErrors.Success)
            {
                //
                // synchronously complete the IO and call the user's callback.
                //
                InvokeCallback(true);
            }
        }
        //
        // AcceptCallback - called by WaitCallback to do special Accept handling
        //   this involves searching through a queue of queued Accept requests
        //   and handling them if there are available accept sockets to handle them,
        //   or rewaiting if they are not
        //
        //  The overlapped function called by the thread pool
        //   when IO completes.
        //

        internal static void AcceptCallback(object stateObject, bool Signaled)
        {
            AcceptAsyncResult thisAsyncResult    = (AcceptAsyncResult)stateObject;
            Socket            socket             = (Socket)thisAsyncResult.AsyncObject;
            Exception         unhandledException = null;

            Monitor.Enter(socket);
            //
            // Accept Callback - called on the callback path, when we expect to release
            //  an accept socket that winsock says has completed.
            //
            //  While we still have items in our Queued list of Accept Requests,
            //   we recall the Winsock accept, to attempt to gather new
            //   results, and then match them again the queued items,
            //   when accept call returns would_block, we reinvoke ourselves
            //   and rewait for the next asyc callback.
            //
            //  If we have emptied the queue, then disable the queue and go back
            //   to sync.
            //
            socket.incallback = true;

            //
            //  Attempt to process queued Accept async
            //
            while (socket.AcceptQueue.Count != 0)    // if ! empty
            //
            // pick an element from the head of the list
            //
            {
                AcceptAsyncResult AResult = (AcceptAsyncResult)socket.AcceptQueue[0];
                socket.AcceptQueue.RemoveAt(0);

                Monitor.Exit(socket);

                int           Status        = SocketErrors.WSAENOTSOCK;
                SocketAddress socketAddress = null;
                IntPtr        AcceptResult  = (IntPtr)0;

                if (!socket.CleanedUp)
                {
                    socketAddress = socket.m_RightEndPoint.Serialize();

                    AcceptResult =
                        UnsafeNclNativeMethods.OSSOCK.accept(
                            socket.m_Handle,
                            socketAddress.m_Buffer,
                            ref socketAddress.m_Size);

                    Status = AcceptResult == SocketErrors.InvalidSocketIntPtr ? Marshal.GetLastWin32Error() : 0;
                }

                GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::AcceptCallback() UnsafeNclNativeMethods.OSSOCK.accept returns:" + Status.ToString());

                //
                // now check for synchronous completion
                //
                if (Status == 0)
                {
                    //
                    // on synchronous completion give our async callback
                    // the accepted Socket right away
                    //

                    try {
                        AResult.InvokeCallback(false, socket.CreateAcceptSocket(AcceptResult, socket.m_RightEndPoint.Create(socketAddress)));
                    } catch (Exception exception) {
                        unhandledException = new InvalidOperationException("AcceptCallback", exception);
                    }
                }
                else if (Status == SocketErrors.WSAEWOULDBLOCK)
                {
                    Monitor.Enter(socket);

                    socket.AcceptQueue.Add(AResult);

                    ThreadPool.RegisterWaitForSingleObject(
                        socket.m_AsyncEvent,
                        new WaitOrTimerCallback(AcceptCallback),
                        thisAsyncResult,
                        -1,
                        true);

                    socket.incallback = false;
                    Monitor.Exit(socket);
                    return;
                }
                else
                {
                    try {
                        AResult.ErrorCode = Status;
                        AResult.InvokeCallback(false, null);
                    } catch (Exception exception) {
                        unhandledException = new InvalidOperationException("AcceptCallback", exception);
                    }
                }
                //
                // Attempt to accept another socket
                //
                Monitor.Enter(socket);
            }

            socket.incallback = false;
            //
            // the accept queue is empty.
            // cancel async event
            //
            socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
            //
            // go back to blocking mode
            //
            socket.InternalSetBlocking(true);

            Monitor.Exit(socket);

            if (unhandledException != null)
            {
                throw unhandledException;
            }
        }
Example #4
0
        //
        // CreateAcceptSocket - pulls unmanaged results and assembles them
        //   into a new Socket object
        //
        internal Socket CreateAcceptSocket(IntPtr fd, EndPoint remoteEP) {
            //
            // Internal state of the socket is inherited from listener
            //
            Socket socket           = new Socket(fd);
            socket.addressFamily    = addressFamily;
            socket.socketType       = socketType;
            socket.protocolType     = protocolType;
            socket.m_LocalEndPoint  = m_LocalEndPoint;
            socket.m_RemoteEndPoint = remoteEP;
            //
            // the socket is connected
            //
            socket.SetToConnected();
            //
            // if the socket is returned by an EndAccept(), the socket might have
            // inherited the WSAEventSelect() call from the accepting socket.
            // we need to cancel this otherwise the socket will be in non-blocking
            // mode and we cannot force blocking mode using the ioctlsocket() in
            // Socket.set_Blocking(), since it fails returing 10022 as documented in MSDN.
            // (note that the m_AsyncEvent event will not be created in this case.
            //
            socket.m_BlockEventBits = m_BlockEventBits;
            socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
            //
            // the new socket will inherit the win32 blocking mode from the accepting socket.
            // if the user desired blocking mode is different from the win32 blocking mode
            // we need to force the desired blocking behaviour.
            //
            socket.willBlock = willBlock;
            if (willBlock!=willBlockInternal) {
                socket.InternalSetBlocking(willBlock);
            }

            return socket;
        }
Example #5
0
        //
        // This is the static internal callback that will be called when
        // the IO we issued for the user to winsock has completed, either
        // synchronously (Signaled=false) or asynchronously (Signaled=true)
        // when this function gets called it must:
        // 1) update the AsyncResult object with the results of the completed IO
        // 2) signal events that the user might be waiting on
        // 3) cal the callback function that the user might have specified
        //
        internal static void ConnectCallback(object stateObject, bool Signaled)
        {
            ConnectAsyncResult asyncResult = stateObject as ConnectAsyncResult;
            Socket             socket      = asyncResult.AsyncObject as Socket;

            GlobalLog.Enter("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", "Signaled:" + Signaled.ToString());

            GlobalLog.Assert(!asyncResult.IsCompleted, "Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() asyncResult.IsCompleted", "");

            //
            // we now need to get the status of the async completion, we had an easy implementation
            // that uses GetSocketOption(), but VadimE suggested not to use this 'cause it may be
            // buggy on some platforms, so we use WSAEnumNetworkEvents() instead:
            //
            // The best way to do this is to call WSAEnumNetworkEvents and use the error code iError
            // array corresponding to FD_CONNECT. getsockopt (SO_ERROR) may return NO_ERROR under
            // stress even in case of error at least on Winnt4.0 (I don't remember whether I fixed
            // it on Win2000 or WinXP).
            //

            //
            // get async completion
            //

            /*
             * int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
             * GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString());
             */

            NetworkEvents networkEvents = new NetworkEvents();

            networkEvents.Events = AsyncEventBits.FdConnect;

            AutoResetEvent chkAsyncEvent = socket.m_AsyncEvent;

            int errorCode = SocketErrors.WSAENOTSOCK;

            if (chkAsyncEvent != null)
            {
                errorCode =
                    UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents(
                        socket.m_Handle,
                        chkAsyncEvent.Handle,
                        ref networkEvents);

                if (errorCode != SocketErrors.Success)
                {
                    errorCode = Marshal.GetLastWin32Error();
                    GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString());
                }
                else
                {
                    errorCode = networkEvents.ErrorCodes[(int)AsyncEventBitsPos.FdConnectBit];
                    GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString());
                }
            }

            try {
                //
                // cancel async event
                //
                socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
                //
                // go back to blocking mode
                //
                socket.InternalSetBlocking(true);
            }
            catch (Exception exception) {
                GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() caught exception::" + exception.Message);
                asyncResult.Result = exception;
            }

            //
            // if the native non-blocking call failed we'll throw a SocketException in EndConnect()
            //
            if (errorCode != SocketErrors.Success)
            {
                //
                // just save the error code, the SocketException will be thrown in EndConnect()
                //
                asyncResult.ErrorCode = errorCode;
            }
            else
            {
                //
                // the Socket is connected, update our state and performance counter
                //
                socket.SetToConnected();
            }

            //
            // call the user's callback now, if there is one.
            //
            asyncResult.InvokeCallback(false);

            GlobalLog.Leave("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", errorCode.ToString());
        }
Example #6
0
        //
        // This is the static internal callback that will be called when
        // the IO we issued for the user to winsock has completed, either
        // synchronously (Signaled=false) or asynchronously (Signaled=true)
        // when this function gets called it must:
        // 1) update the AsyncResult object with the results of the completed IO
        // 2) signal events that the user might be waiting on
        // 3) cal the callback function that the user might have specified
        //
        internal static void ConnectCallback(object stateObject, bool Signaled)
        {
            ConnectAsyncResult asyncResult = stateObject as ConnectAsyncResult;
            Socket             socket      = asyncResult.AsyncObject as Socket;

            GlobalLog.Enter("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", "Signaled:" + Signaled.ToString());

            GlobalLog.Assert(!asyncResult.IsCompleted, "Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() asyncResult.IsCompleted", "");

            //

            //
            // get async completion
            //

            /*
             * int errorCode = (int)socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Error);
             * GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() GetSocketOption() returns errorCode:" + errorCode.ToString());
             */

            NetworkEvents networkEvents = new NetworkEvents();

            networkEvents.Events = AsyncEventBits.FdConnect;

            AutoResetEvent chkAsyncEvent = socket.m_AsyncEvent;

            int errorCode = SocketErrors.WSAENOTSOCK;

            if (chkAsyncEvent != null)
            {
                errorCode =
                    UnsafeNclNativeMethods.OSSOCK.WSAEnumNetworkEvents(
                        socket.m_Handle,
                        chkAsyncEvent.Handle,
                        ref networkEvents);

                if (errorCode != SocketErrors.Success)
                {
                    errorCode = Marshal.GetLastWin32Error();
                    GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() WSAEnumNetworkEvents() failed with errorCode:" + errorCode.ToString());
                }
                else
                {
                    errorCode = networkEvents.ErrorCodes[(int)AsyncEventBitsPos.FdConnectBit];
                    GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() ErrorCodes(FdConnect) got errorCode:" + errorCode.ToString());
                }
            }

            try {
                //
                // cancel async event
                //
                socket.SetAsyncEventSelect(AsyncEventBits.FdNone);
                //
                // go back to blocking mode
                //
                socket.InternalSetBlocking(true);
            }
            catch (Exception exception) {
                GlobalLog.Print("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback() caught exception::" + exception.Message);
                asyncResult.Result = exception;
            }

            //
            // if the native non-blocking call failed we'll throw a SocketException in EndConnect()
            //
            if (errorCode != SocketErrors.Success)
            {
                //
                // just save the error code, the SocketException will be thrown in EndConnect()
                //
                asyncResult.ErrorCode = errorCode;
            }
            else
            {
                //
                // the Socket is connected, update our state and performance counter
                //
                socket.SetToConnected();
            }

            //
            // call the user's callback now, if there is one.
            //
            asyncResult.InvokeCallback(false);

            GlobalLog.Leave("Socket#" + ValidationHelper.HashString(socket) + "::ConnectCallback", errorCode.ToString());
        }