Search code examples
.netsocketscompact-framework

.NET CF - Socket.BeginReceive - Does this ever throw a SocketException?


I have been looking at how calling BeginReceive on a .NET CF socket can throw an SocketException as per http://msdn.microsoft.com/en-us/library/dxkwh6zw(v=vs.90).aspx?

I looked through the Reflector but I cannot see how this is possible? I think the SocketException is only possible while actually doing the work in a threadpool thread.

My guess is any SocketException is channel through EndReceive().

I have a callback method which calls itself (i.e. BeginReceive(.., .., callback), which contains an EndReceive. I want to make sure that I add a Try-catch in the right place.

Any ideas?


Solution

  • I looked at the .NET Reference Source and it will throw an exception.

    Code:

    [HostProtection(ExternalThreading=true)] 
        public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
        { 
            SocketError errorCode;
            IAsyncResult result = BeginReceive(buffer, offset, size, socketFlags, out errorCode, callback, state);
            if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
                throw new SocketException(errorCode); 
            }
            return result; 
        } 
    

    In a method that gets called from overloads of the Begin in a method called DoBeginReceive this method calls this code. The errorcode is passed using the out keyword so it is exactly what is passed back.

    errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv(
                    m_Handle, 
                    ref asyncResult.m_SingleBuffer,
                    1,
                    out bytesTransferred,
                    ref socketFlags, 
                    asyncResult.OverlappedHandle,
                    IntPtr.Zero); 
    

    EDIT: For .NET CF:

    As Stated by the OP

    This is the Begin Receive

    public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
    {
        this.throwIfDisposed();
        if (buffer == null)
        {
            throw new ArgumentNullException("buffer");
        }
        if (offset < 0)
        {
            throw new ArgumentOutOfRangeException("offset");
        }
        if (size < 0)
        {
            throw new ArgumentOutOfRangeException("size");
        }
        if (buffer.Length < (offset + size))
        {
            throw new ArgumentOutOfRangeException("", SR.GetString(0x41, new object[0]));
        }
        ReceiveAsyncRequest req = new ReceiveAsyncRequest(this, buffer, offset, size, socketFlags, callback, state);
        this.addReadRequest(req);
        return req;
    }
    

    The addReadRequest does this:

    private void addReadRequest(AsyncRequest req)
    {
        lock (this)
        {
            if (this.m_readHead == null)
            {
                if (!startWorker(req))
                {
                    req.InvokeCallback(false, new OutOfMemoryException(SR.GetString(0x42, new object[0])));
                }
                else
                {
                    this.m_readHead = req;
                }
            }
            else
            {
                AsyncRequest readHead = this.m_readHead;
                while (readHead.m_next != null)
                {
                    readHead = readHead.m_next;
                }
                readHead.m_next = req;
            }
        }
    }
    

    The startWorker does this:

    private static bool startWorker(AsyncRequest req)
    {
        WorkerThread thread = new WorkerThread(req);
        if (!ThreadPool.QueueUserWorkItem(new WaitCallback(thread.doWorkI)))
        {
            return false;
        }
        return true;
    }
    

    The Thread calls the doWork of the ReceiveAsyncRequestcalls the doRequest of the ReceiveAsyncRequestwhich calls the handleRequest which in turn calls doRequest on the ReceiveAsyncRequest.

    The doRequest of the ReceiveAsyncRequest method looks like this:

    protected override object doRequest()
    {
        return base.m_socket.ReceiveNoCheck(this.m_readBuffer, this.m_index, this.m_size, this.m_flags);
    }
    

    In the ReceiveFromNoCheck it throws the exception:

    internal int ReceiveFromNoCheck(byte[] buffer, int index, int request, SocketFlags flags)
    {
        this.throwIfDisposed();
        int rc = 0;
        int num2 = OSSOCK.recv(this.handle, buffer, index, request, (int) flags, ref rc);
        if(num2 < 0)
        {
            throw new SocketException(rc);
        }
        return num2;
    }
    

    If the AsyncResults runs sychronously, it will throw the exception. However, if it is part of the ThreadPool, the exception will just be thrown and kill the application.