int UdpClientTransport::receive(
        I_ClientTransportCallback &clientStub, 
        ByteBuffer &byteBuffer,
        unsigned int timeoutMs)
    {
        // try to receive a UDP message from server, within the current timeout
        RCF_LOG_4()(mSock)(mDestIp.string())(timeoutMs) << "UdpClientTransport - receiving data from socket.";

        RCF_ASSERT(!mAsync);

        unsigned int startTimeMs = getCurrentTimeMs();
        unsigned int endTimeMs = startTimeMs + timeoutMs;

        while (true)
        {
            unsigned int timeoutMs = generateTimeoutMs(endTimeMs);
            fd_set fdSet;
            FD_ZERO(&fdSet);
            FD_SET( static_cast<SOCKET>(mSock), &fdSet);
            timeval timeout;
            timeout.tv_sec = timeoutMs/1000;
            timeout.tv_usec = 1000*(timeoutMs%1000);

            int ret = Platform::OS::BsdSockets::select(
                mSock+1,
                &fdSet,
                NULL,
                NULL,
                &timeout);

            int err = Platform::OS::BsdSockets::GetLastError();

            RCF_ASSERT(-1 <= ret && ret <= 1)(ret);
            if (ret == -1)
            {
                Exception e(
                    _RcfError_Socket("select()"),
                    err,
                    RcfSubsystem_Os);

                RCF_THROW(e);
            }   
            else if (ret == 0)
            {
                Exception e( _RcfError_ClientReadTimeout() );
                RCF_THROW(e);
            }
            RCF_ASSERT_EQ(ret , 1);

            if (mReadVecPtr.get() == NULL || !mReadVecPtr.unique())
            {
                mReadVecPtr.reset( new ReallocBuffer());
            }

            // TODO: optimize
            ReallocBuffer &buffer = *mReadVecPtr;
            buffer.resize(4);

            SockAddrStorage fromAddr;
            memset(&fromAddr, 0, sizeof(fromAddr));
            int fromAddrLen = sizeof(fromAddr);

            sockaddr * pDestAddr = NULL;
            Platform::OS::BsdSockets::socklen_t destAddrSize = 0;
            mDestIp.getSockAddr(pDestAddr, destAddrSize);

            int len = Platform::OS::BsdSockets::recvfrom(
                mSock,
                &buffer[0],
                4,
                MSG_PEEK,
                (sockaddr *) &fromAddr,
                &fromAddrLen);

            err = Platform::OS::BsdSockets::GetLastError();

            if (    len == 4 
                ||  (len == -1 && err == Platform::OS::BsdSockets::ERR_EMSGSIZE))
            {
                mFromIp.init( (sockaddr&) fromAddr, fromAddrLen, mDestIp.getType());
                if (mDestIp.matches(mFromIp))
                {
                    boost::uint32_t dataLength = 0;
                    memcpy( &dataLength, &buffer[0], 4);
                    RCF::networkToMachineOrder(&dataLength, 4, 1);

                    if (getMaxMessageLength())
                    {
                        RCF_VERIFY(
                            0 < dataLength && dataLength <= getMaxMessageLength(),
                            Exception(_RcfError_ClientMessageLength(dataLength, getMaxMessageLength())));
                    }

                    buffer.resize(4+dataLength);
                    memset(&fromAddr, 0, sizeof(fromAddr));
                    fromAddrLen = sizeof(fromAddr);

                    len = Platform::OS::BsdSockets::recvfrom(
                        mSock,
                        &buffer[0],
                        dataLength+4,
                        0,
                        (sockaddr *) &fromAddr,
                        &fromAddrLen);

                    if (len == static_cast<int>(dataLength+4))
                    {
                        mLastResponseSize = dataLength+4;
                        mRunningTotalBytesReceived += dataLength+4;

                        byteBuffer = ByteBuffer(
                            &buffer[4],
                            dataLength,
                            4,
                            mReadVecPtr);

                        clientStub.onReceiveCompleted();

                        return 1;
                    }
                }
                else
                {
                    // The packet is not a valid response, but we need to read
                    // it so we can receive more packets.

                    const std::size_t BufferSize = 4096;
                    char Buffer[BufferSize];
                    Platform::OS::BsdSockets::recvfrom(
                        mSock,
                        Buffer,
                        BufferSize,
                        0,
                        NULL,
                        NULL);
                }
            }
            else
            {
                RCF_THROW( Exception( _RcfError_ClientReadFail() ) )(len)(err);
            }
        }
    }
    std::size_t Win32NamedPipeClientTransport::implRead(
        const ByteBuffer &byteBuffer,
        std::size_t bytesRequested)
    {
        // For now, can't go back to sync calls after doing an async call.
        // Limitations with Windows IOCP.
        RCF_ASSERT(!mAsyncMode);

        std::size_t bytesToRead = RCF_MIN(bytesRequested, byteBuffer.getLength());

        BOOL ok = ResetEvent(mhEvent);
        DWORD dwErr = GetLastError();
        RCF_VERIFY(ok, Exception(_RcfError_Pipe(), dwErr));

        OVERLAPPED overlapped = {0};
        overlapped.hEvent = mhEvent;

        DWORD dwRead = 0;
        DWORD dwBytesToRead = static_cast<DWORD>(bytesToRead);

        ok = ReadFile(
            mhPipe, 
            byteBuffer.getPtr(), 
            dwBytesToRead, 
            &dwRead, 
            &overlapped);
        
        dwErr = GetLastError();

        if (!ok)
        {
            RCF_VERIFY( 
                dwErr == ERROR_IO_PENDING ||
                dwErr == WSA_IO_PENDING ||
                dwErr == ERROR_MORE_DATA,
                Exception(_RcfError_ClientReadFail(), dwErr));
        }

        ClientStub & clientStub = *getTlsClientStubPtr();

        DWORD dwRet = WAIT_TIMEOUT;
        while (dwRet == WAIT_TIMEOUT)
        {
            boost::uint32_t timeoutMs = generateTimeoutMs(mEndTimeMs);
            timeoutMs = clientStub.generatePollingTimeout(timeoutMs);

            dwRet = WaitForSingleObject(overlapped.hEvent, timeoutMs);
            dwErr = GetLastError();

            RCF_VERIFY( 
                dwRet == WAIT_OBJECT_0 || dwRet == WAIT_TIMEOUT, 
                Exception(_RcfError_Pipe(), dwErr));

            RCF_VERIFY(
                generateTimeoutMs(mEndTimeMs),
                Exception(_RcfError_ClientReadTimeout()))
                (mEndTimeMs)(bytesToRead);

            if (dwRet == WAIT_TIMEOUT)
            {
                clientStub.onPollingTimeout();
            }
        }
        RCF_ASSERT_EQ(dwRet , WAIT_OBJECT_0);

        dwRead = 0;
        ok = GetOverlappedResult(mhPipe, &overlapped, &dwRead, FALSE);
        dwErr = GetLastError();
        RCF_VERIFY(ok && dwRead > 0, Exception(_RcfError_Pipe(), dwErr));

        onTimedRecvCompleted(dwRead, 0);

        return dwRead;
    }
    void OverlappedAmi::onCompletion(
        std::size_t index,
        const AsioErrorCode & ec, 
        std::size_t bytesTransferred)
    {
        RecursiveLock lock(mMutex);

        if (mIndex == index && mpTransport)
        {
            ++mIndex;

            if (mpTransport->mAsioTimerPtr)
            {
                mpTransport->mAsioTimerPtr->cancel();
            }

#ifdef BOOST_WINDOWS
            // Do we need to impersonate?
            boost::scoped_ptr<Win32ThreadImpersonator> impersonator;
            HANDLE hImpersonationToken = static_cast<ClientStub *>(mpTransport->mpClientStub)
                ->getWindowsImpersonationToken();
            if (hImpersonationToken != INVALID_HANDLE_VALUE)
            {
                impersonator.reset( new Win32ThreadImpersonator(hImpersonationToken) );
            }
#endif

            if (ec)
            {
                try
                {
                    RCF::Exception e;

                    switch (mOpType)
                    {
                    case Wait:
                        RCF_ASSERT(0);
                        break;

                    case Connect:
                        e = RCF::Exception( _RcfError_ClientConnectFail(), ec.value());
                        break;

                    case Write:
                        e = RCF::Exception( _RcfError_ClientWriteFail(), ec.value());
                        break;

                    case Read:
                        e = RCF::Exception( _RcfError_ClientReadFail(), ec.value());
                        break;

                    default:
                        RCF_ASSERT(0);
                    };

                    mOpType = None;

                    mpTransport->mpClientStub->onError(e);
                }
                catch(const std::exception &e)
                {
                    mpTransport->mpClientStub->onError(e);
                }
                catch(...)
                {
                    RCF::Exception e( _RcfError_NonStdException() );
                    mpTransport->mpClientStub->onError(e);
                }
            }
            else
            {
                mOpType = None;

                try
                {
                    mpTransport->onCompletion( static_cast<int>(bytesTransferred) );
                }
                catch(const std::exception &e)
                {
                    mpTransport->mpClientStub->onError(e);
                }
                catch(...)
                {
                    RCF::Exception e( _RcfError_NonStdException() );
                    mpTransport->mpClientStub->onError(e);
                }
            }

            getTlsAmiNotification().run();
        }

    }