int UdpClientTransport::send(
        I_ClientTransportCallback &clientStub, 
        const std::vector<ByteBuffer> &data,
        unsigned int timeoutMs)
    {
        RCF_LOG_4()(mSock)(mDestIp.string()) << "UdpClientTransport - sending data on socket.";

        RCF_UNUSED_VARIABLE(timeoutMs);

        RCF_ASSERT(!mAsync);

        // TODO: optimize for case of single byte buffer with left margin

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

        mLastRequestSize = lengthByteBuffers(data);
        mRunningTotalBytesSent += lengthByteBuffers(data);

        ReallocBuffer &buffer = *mWriteVecPtr;
        buffer.resize(lengthByteBuffers(data));

        copyByteBuffers(data, &buffer[0]);

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

        int len = sendto(
            mSock,
            &buffer[0],
            static_cast<int>(buffer.size()),
            0,
            pDestAddr, 
            destAddrSize);

        int err = Platform::OS::BsdSockets::GetLastError();
        RCF_VERIFY(
            len > 0,
            Exception(
                _RcfError_Socket("sendto()"),
                err,
                RcfSubsystem_Os));

        clientStub.onSendCompleted();

        return 1;
    }
Example #2
0
    void HttpSessionFilter::write(const std::vector<ByteBuffer> &byteBuffers)
    {
        // If we write the response directly to network here, we ar at risk of a race
        // condition as the next request may be read in on another connection, before
        // the write completion on this connection has executed.

        // So instead we make a copy of the write buffers, and send a write completion
        // back up. The subsequent read operation will unhook the HTTP session and then 
        // write the response to the network.

        if ( mNetworkSession.mCloseAfterWrite )
        {
            // Special case, if this is the last message being written before the connection closes.
            mpPostFilter->write(byteBuffers);
        }
        else
        {
            std::size_t len = lengthByteBuffers(byteBuffers);
            ReallocBufferPtr bufferPtr = getObjectPool().getReallocBufferPtr();
            bufferPtr->resize(len);
            copyByteBuffers(byteBuffers, bufferPtr->getPtr());
            mWriteBuffers.resize(0);
            mWriteBuffers.push_back(ByteBuffer(bufferPtr));

            mpPreFilter->onWriteCompleted(len);
        }
    }
Example #3
0
        void write(const std::vector<ByteBuffer> &byteBuffers)
        {
            std::copy(
                byteBuffers.begin(),
                byteBuffers.end(),
                std::back_inserter(mByteBuffers));

            std::size_t bytesTransferred = lengthByteBuffers(byteBuffers);
            getPreFilter().onWriteCompleted(bytesTransferred);
        }
Example #4
0
    void copyByteBuffers(
        const std::vector<ByteBuffer> &byteBuffers,
        ByteBuffer &byteBuffer)
    {
        boost::shared_ptr<std::vector<char> > vecPtr(
            new std::vector<char>(lengthByteBuffers(byteBuffers)));

        copyByteBuffers(byteBuffers, &(*vecPtr)[0]);
        byteBuffer = ByteBuffer(
            &(*vecPtr)[0],
            (*vecPtr).size(),
            vecPtr);
    }
void AsioSessionState::beginWrite()
{
    mSlicedWriteByteBuffers.resize(0);

    sliceByteBuffers(
        mSlicedWriteByteBuffers,
        mWriteByteBuffers,
        lengthByteBuffers(mWriteByteBuffers)-mWriteBufferRemaining);

    mTransportFilters.empty() ?
    write(mSlicedWriteByteBuffers) :
    mTransportFilters.front()->write(mSlicedWriteByteBuffers);
}
    void UdpSessionState::postWrite(
        std::vector<ByteBuffer> &byteBuffers)
    {
        // prepend data length and send the data

        boost::shared_ptr<std::vector<char> > &writeVecPtr = mWriteVecPtr;

        if (writeVecPtr.get() == NULL || !writeVecPtr.unique())
        {
            writeVecPtr.reset( new std::vector<char>());
        }

        std::vector<char> &writeBuffer = *writeVecPtr;

        unsigned int dataLength = static_cast<unsigned int>(
            lengthByteBuffers(byteBuffers));

        writeBuffer.resize(4+dataLength);
        memcpy( &writeBuffer[0], &dataLength, 4);
        machineToNetworkOrder(&writeBuffer[0], 4, 1);
        copyByteBuffers(byteBuffers, &writeBuffer[4]);
        byteBuffers.resize(0);

        const sockaddr_in &remoteAddr = remoteAddress.getSockAddr();
       
        int len = sendto(
            mTransport.mFd,
            &writeBuffer[0],
            static_cast<int>(writeBuffer.size()),
            0,
            (const sockaddr *) &remoteAddr,
            sizeof(remoteAddr));

        if (len != static_cast<int>(writeBuffer.size()))
        {
            int err = Platform::OS::BsdSockets::GetLastError();
            RCF_THROW(Exception(
                RcfError_Socket, err, RcfSubsystem_Os, "sendto() failed"))
                (mTransport.mFd)(len)(writeBuffer.size());
        }

        SessionStatePtr sessionStatePtr = getCurrentUdpSessionStatePtr();

        SessionPtr sessionPtr = sessionStatePtr->mSessionPtr;

        RcfSessionPtr rcfSessionPtr = 
            boost::static_pointer_cast<RcfSession>(sessionPtr);

        rcfSessionPtr->mIoState = RcfSession::Reading;
    }
    void ZlibCompressionWriteFilter::onWriteCompleted(
        std::size_t bytesTransferred)
    {
        // 1. if partial buffer was written -> write remaining part of buffer
        // 2. if whole buffer was written -> check if any more compression or writing is needed
        // 3. if no more compression or writing needed, notify previous filter of completion

        RCF_ASSERT_LTEQ(bytesTransferred , lengthByteBuffers(mPostBuffers));

        if (bytesTransferred < lengthByteBuffers(mPostBuffers))
        {
            // TODO: optimize
            std::vector<ByteBuffer> slicedBuffers;
            sliceByteBuffers(slicedBuffers, mPostBuffers, bytesTransferred);
            mPostBuffers = slicedBuffers;
            mFilter.getPostFilter().write(mPostBuffers);
        }
        else
        {
            mPreBuffers.resize(0);
            mPostBuffers.resize(0);
            mFilter.getPreFilter().onWriteCompleted(mTotalBytesIn);
        }
    }
    void AsioSessionState::invokeAsyncWrite()
    {
        RCF2_TRACE("")(this);

        mSlicedWriteByteBuffers.resize(0);

        sliceByteBuffers(
            mSlicedWriteByteBuffers,
            mWriteByteBuffers,
            lengthByteBuffers(mWriteByteBuffers)-mWriteBufferRemaining);

        mTransportFilters.empty() ?
            write(mSlicedWriteByteBuffers) :
            mTransportFilters.front()->write(mSlicedWriteByteBuffers);

    }
    void UdpSessionState::postWrite(
        std::vector<ByteBuffer> &byteBuffers)
    {
        // prepend data length and send the data

        ReallocBufferPtr &writeVecPtr = mWriteVecPtr;

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

        ReallocBuffer &writeBuffer = *writeVecPtr;

        unsigned int dataLength = static_cast<unsigned int>(
            lengthByteBuffers(byteBuffers));

        writeBuffer.resize(4+dataLength);
        memcpy( &writeBuffer[0], &dataLength, 4);
        machineToNetworkOrder(&writeBuffer[0], 4, 1);
        copyByteBuffers(byteBuffers, &writeBuffer[4]);
        byteBuffers.resize(0);

        sockaddr * pRemoteAddr = NULL;
        Platform::OS::BsdSockets::socklen_t remoteAddrSize = 0;
        mRemoteAddress.getSockAddr(pRemoteAddr, remoteAddrSize);
       
        int len = sendto(
            mTransport.mFd,
            &writeBuffer[0],
            static_cast<int>(writeBuffer.size()),
            0,
            pRemoteAddr,
            remoteAddrSize);

        if (len != static_cast<int>(writeBuffer.size()))
        {
            int err = Platform::OS::BsdSockets::GetLastError();
            Exception e(_RcfError_Socket("sendto()"), err, RcfSubsystem_Os);
            RCF_THROW(e)(mTransport.mFd)(len)(writeBuffer.size());
        }

        SessionStatePtr sessionStatePtr = getTlsUdpSessionStatePtr();

        SessionPtr sessionPtr = sessionStatePtr->mSessionPtr;
    }
Example #10
0
    bool filterData(
        const std::vector<ByteBuffer> &unfilteredData,
        std::vector<ByteBuffer> &filteredData,
        const std::vector<FilterPtr> &filters)
    {
        std::size_t bytesTransferred        = 0;
        std::size_t bytesTransferredTotal   = 0;

        WriteProxy writeProxy;
        writeProxy.setPreFilter(*filters.back());
        filters.back()->setPostFilter(writeProxy);
        filters.front()->setPreFilter(writeProxy);

        std::size_t unfilteredDataLen = lengthByteBuffers(unfilteredData);
        while (bytesTransferredTotal < unfilteredDataLen)
        {

            ThreadLocalCached< std::vector<ByteBuffer> > tlcSlicedByteBuffers;
            std::vector<ByteBuffer> &slicedByteBuffers = tlcSlicedByteBuffers.get();
            sliceByteBuffers(slicedByteBuffers, unfilteredData, bytesTransferredTotal);
            filters.front()->write(slicedByteBuffers);

            // TODO: error handling
            bytesTransferred = writeProxy.getBytesTransferred();
            bytesTransferredTotal += bytesTransferred;
        }
        RCF_ASSERT_EQ(bytesTransferredTotal , unfilteredDataLen);

        filteredData.resize(0);

        std::copy(
            writeProxy.getByteBuffers().begin(),
            writeProxy.getByteBuffers().end(),
            std::back_inserter(filteredData));

        return bytesTransferredTotal == unfilteredDataLen;
    }
Example #11
0
    // returns -2 for timeout, -1 for error, otherwise number of bytes sent (> 0)
    int timedSend(
        I_PollingFunctor &pollingFunctor,
        int &err,
        int fd,
        const std::vector<ByteBuffer> &byteBuffers,
        std::size_t maxSendSize,
        int flags)
    {
        RCF_UNUSED_VARIABLE(flags);
        std::size_t bytesRemaining = lengthByteBuffers(byteBuffers);
        std::size_t bytesSent = 0;
        while (true)
        {
            std::size_t bytesToSend = RCF_MIN(bytesRemaining, maxSendSize);

            ThreadLocalCached< std::vector<WSABUF> > tlcWsabufs;
            std::vector<WSABUF> &wsabufs = tlcWsabufs.get();

            forEachByteBuffer(
                boost::bind(&appendWsabuf, boost::ref(wsabufs), _1),
                byteBuffers,
                bytesSent,
                bytesToSend);

            int count = 0;
            int myErr = 0;

#ifdef BOOST_WINDOWS
            {
                DWORD cbSent = 0;
                int ret = WSASend(
                    fd, 
                    &wsabufs[0], 
                    static_cast<DWORD>(wsabufs.size()), 
                    &cbSent, 
                    0, 
                    NULL, 
                    NULL);

                count = (ret == 0) ? cbSent : -1;
                myErr = Platform::OS::BsdSockets::GetLastError();
            }            
#else
            {
                msghdr hdr = {0};
                hdr.msg_iov = &wsabufs[0];
                hdr.msg_iovlen = wsabufs.size();
                count = sendmsg(fd, &hdr, 0);
                myErr = Platform::OS::BsdSockets::GetLastError();
            }
#endif

            if (count >= 0)
            {
                RCF_ASSERT_LTEQ(count , static_cast<int>(bytesRemaining));

                bytesRemaining -= count;
                bytesSent += count;
                err = 0;
                return static_cast<int>(bytesSent);
            }
            else if (myErr == Platform::OS::BsdSockets::ERR_EWOULDBLOCK)
            {
                // can't get WSA_IO_PENDING here, since the socket isn't overlapped
                int ret = pollingFunctor(fd, myErr, false);
                if (ret  != 0)
                {
                    err = myErr;
                    return ret;
                }
            }
            else
            {
                err = myErr;
                return -1;
            }


        }
    }
    void ZlibCompressionWriteFilter::compress()
    {
        mPostBuffers.resize(0);

        // TODO: buffer size
        std::size_t bufferSize = 2*(lengthByteBuffers(mPreBuffers)+7+7);
        std::size_t leftMargin = mPreBuffers.front().getLeftMargin();

        if (mVecPtr.get() == NULL || !mVecPtr.unique())
        {
            mVecPtr.reset( new ReallocBuffer());
        }
        mVecPtr->resize(leftMargin + bufferSize);

        if (leftMargin > 0)
        {
            mPostBuffers.push_back(
                ByteBuffer(
                    &(*mVecPtr)[0] + leftMargin,
                    mVecPtr->size() - leftMargin,
                    leftMargin,
                    mVecPtr));
        }
        else
        {
            mPostBuffers.push_back(
                ByteBuffer(
                    &(*mVecPtr)[0],
                    mVecPtr->size(),
                    mVecPtr));
        }

        ByteBuffer &outBuffer = mPostBuffers.back();
        std::size_t outPos = 0;
        std::size_t outRemaining = outBuffer.getLength() - outPos;
        mTotalBytesIn = 0;
        mTotalBytesOut = 0;

        for (std::size_t i=0; i<mPreBuffers.size(); ++i)
        {
            RCF_ASSERT_LT(outPos , outBuffer.getLength());

            ByteBuffer &inBuffer = mPreBuffers[i];
            mCstream.next_in = (Bytef*) inBuffer.getPtr();
            mCstream.avail_in = static_cast<uInt>(inBuffer.getLength());
            mCstream.next_out = (Bytef*) &outBuffer.getPtr()[outPos];
            mCstream.avail_out = static_cast<uInt>(outRemaining);

            mZerr = (i<mPreBuffers.size()-1) ?
                deflate(&mCstream, Z_NO_FLUSH) :
                deflate(&mCstream, Z_SYNC_FLUSH);

            RCF_VERIFY(
                mZerr == Z_OK || mZerr == Z_BUF_ERROR,
                FilterException(
                    _RcfError_Zlib(), mZerr, RcfSubsystem_Zlib,
                    "deflate() failed"))
                (mZerr)(inBuffer.getLength())(outBuffer.getLength());

            RCF_ASSERT_GTEQ(mCstream.avail_out , 0);

            std::size_t bytesIn = inBuffer.getLength() - mCstream.avail_in;
            std::size_t bytesOut = outRemaining - mCstream.avail_out;
            mTotalBytesIn += bytesIn;
            mTotalBytesOut += bytesOut;
            outPos += bytesOut;
            outRemaining -= bytesOut;
        }

        if (!mStateful)
        {
            mCstream.next_in = NULL;
            mCstream.avail_in = 0;
            mCstream.next_out = (Bytef*) &outBuffer.getPtr()[outPos];
            mCstream.avail_out = static_cast<uInt>(outRemaining);

            mZerr = deflate(&mCstream, Z_FINISH);
            RCF_VERIFY(
                mZerr == Z_BUF_ERROR || mZerr == Z_STREAM_END,
                FilterException(
                    _RcfError_Zlib(), mZerr, RcfSubsystem_Zlib,
                    "deflate() failed"))
                    (mZerr)(outPos)(outRemaining);

            RCF_ASSERT_GT(mCstream.avail_out , 0);

            std::size_t bytesOut = outRemaining - mCstream.avail_out;
            mTotalBytesOut += bytesOut;
            outPos += bytesOut;
            outRemaining -= bytesOut;
        }

        mPreBuffers.resize(0);
        outBuffer = ByteBuffer(outBuffer, 0, mTotalBytesOut);
    }
    int MulticastClientTransport::send(
        ClientTransportCallback &           clientStub,
        const std::vector<ByteBuffer> &     data,
        unsigned int                        timeoutMs)
    {
        // NB: As the same buffer is sent on all transports, the transports and
        // filters should never modify the buffer. Any transport that transforms
        // data needs to do so in a separate per-transport buffer.

        RCF_UNUSED_VARIABLE(timeoutMs);

        RCF_LOG_2()(lengthByteBuffers(data))(timeoutMs) 
            << "MulticastClientTransport::send() - entry.";

        mLastRequestSize = lengthByteBuffers(data);
        mRunningTotalBytesSent += mLastRequestSize;

        bringInNewTransports();

        Lock lock(mClientTransportsMutex);

        std::size_t transportsInitial = mClientTransports.size();

        PublishCompletionInfo info( mClientTransports.size() );

        // Setup completion handlers.
        std::vector<PublishCompletionHandler> handlers( mClientTransports.size() );
        for (std::size_t i=0; i<mClientTransports.size(); ++i)
        {
            ClientTransport * pTransport = (*mClientTransports[i]).get();
            handlers[i] = PublishCompletionHandler(pTransport, &info);
        }

        // Async send on all transports.
        for (std::size_t i=0; i<handlers.size(); ++i)
        {
            try
            {

                handlers[i].mpClientTransport->setAsync(true);
                handlers[i].mpClientTransport->send(handlers[i], data, 0);
            }
            catch(const Exception &e)
            {
                Exception err( _RcfError_SyncPublishError(e.what()) );
                handlers[i].onError(err);
            }
        }

        // Wait for async completions.
        boost::uint32_t completionDurationMs = 0;
        {
            Timer timer;
            info.wait(timeoutMs);
            completionDurationMs = timer.getDurationMs();
        }

        // Cancel any outstanding sends.
        for (std::size_t i=0; i<handlers.size(); ++i)
        {
            if (!handlers[i].mCompleted)
            {
                (*mClientTransports[i])->cancel();

                RCF_LOG_2()(i)
                    << "MulticastClientTransport::send() - cancel send.";
            }
        }

        // Wait for canceled ops to complete.
        boost::uint32_t cancelDurationMs = 0;
        {
            Timer timer;
            info.wait(timeoutMs);
            cancelDurationMs = timer.getDurationMs();
        }

        RCF_ASSERT(info.getCompletionCount() == handlers.size());

        // Close and remove any subscriber transports with errors.
        std::size_t transportsRemoved = 0;
        for (std::size_t i=0; i<handlers.size(); ++i)
        {
            RCF_ASSERT(handlers[i].mCompleted);
            if (!handlers[i].mOk)
            {
                mClientTransports[i] = ClientTransportAutoPtrPtr();
                ++transportsRemoved;

                RCF_LOG_2()(i)(handlers[i].mCompleted)(handlers[i].mOk)(handlers[i].mError) 
                    << "MulticastClientTransport::send() - remove subscriber transport.";
            }
        }
        eraseRemove(mClientTransports, ClientTransportAutoPtrPtr());

        clientStub.onSendCompleted();

        std::size_t transportsFinal = transportsInitial - transportsRemoved;

        RCF_LOG_2()
            (lengthByteBuffers(data))(completionDurationMs)(cancelDurationMs)(transportsInitial)(transportsFinal)
            << "MulticastClientTransport::send() - exit.";

        return 1;
    }