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; }
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); } }
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); }
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; }
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; }
// 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; }