std::size_t Win32NamedPipeClientTransport::implWrite( const std::vector<ByteBuffer> &byteBuffers) { // For now, can't go back to sync calls after doing an async call. // Limitations with Windows IOCP. RCF_ASSERT(!mAsyncMode); // Not using overlapped I/O here because it interferes with the // server session that might be coupled to this transport. const ByteBuffer & byteBuffer = byteBuffers.front(); DWORD count = 0; DWORD dwBytesToWrite = static_cast<DWORD>(byteBuffer.getLength()); BOOL ok = WriteFile( mhPipe, byteBuffer.getPtr(), dwBytesToWrite, &count, NULL); DWORD dwErr = GetLastError(); RCF_VERIFY(ok, Exception(_RcfError_ClientWriteFail(), dwErr)); // Strangely, WriteFile() sometimes returns 1, but at the same time a much too big value in count. RCF_VERIFY(count <= dwBytesToWrite, Exception(_RcfError_ClientWriteFail(), dwErr))(count)(dwBytesToWrite); RCF_VERIFY(count > 0, Exception(_RcfError_ClientWriteFail(), dwErr))(count)(dwBytesToWrite); onTimedSendCompleted( RCF_MIN(count, dwBytesToWrite), 0); return count; }
boost::uint32_t ClientStub::generatePollingTimeout(boost::uint32_t timeoutMs) { boost::uint32_t timeNowMs = RCF::getCurrentTimeMs(); boost::uint32_t timeToNextTimerCallbackMs = mNextTimerCallbackMs ? mNextTimerCallbackMs - timeNowMs: boost::uint32_t(-1); boost::uint32_t timeToNextPingBackCheckMs = mNextPingBackCheckMs ? mNextPingBackCheckMs - timeNowMs: boost::uint32_t(-1); return RCF_MIN( RCF_MIN(timeToNextTimerCallbackMs, timeToNextPingBackCheckMs), timeoutMs); }
bool PingBackService::cycle( int timeoutMs, const volatile bool &stopFlag) { mTimerHeap.rebase(); PingBackTimerEntry entry; while ( !stopFlag && !mStopFlag && mTimerHeap.getExpiredEntry(entry)) { // Is the session still alive? RcfSessionPtr rcfSessionPtr( entry.second.lock() ); if (rcfSessionPtr) { Lock lock(rcfSessionPtr->mIoStateMutex); // Is the timer entry still there? It can't change while we hold mIoStateMutex. if (mTimerHeap.compareTop(entry)) { // Calculate the next ping back time. boost::uint32_t pingBackIntervalMs = rcfSessionPtr->getPingBackIntervalMs(); pingBackIntervalMs = RCF_MAX(pingBackIntervalMs, boost::uint32_t(1000)); boost::uint32_t nextFireMs = Platform::OS::getCurrentTimeMs() + pingBackIntervalMs; PingBackTimerEntry nextEntry(nextFireMs, rcfSessionPtr); mTimerHeap.remove(entry); mTimerHeap.add(nextEntry); rcfSessionPtr->mPingBackTimerEntry = nextEntry; // Only send a pingback, if previous one has completed. if (!rcfSessionPtr->mWritingPingBack) { rcfSessionPtr->sendPingBack(); } mTimerHeap.add(nextEntry); } } } boost::uint32_t queueTimeoutMs = RCF_MIN( static_cast<boost::uint32_t>(timeoutMs), mTimerHeap.getNextEntryTimeoutMs()); if (!stopFlag && !mStopFlag) { Lock lock(mMutex); mCondition.timed_wait(lock, queueTimeoutMs); } return stopFlag || mStopFlag; }
void read(const ByteBuffer &byteBuffer, std::size_t bytesRequested) { RCF_ASSERT(byteBuffer.isEmpty())(byteBuffer.getLength()); RCF_ASSERT_LT(mInByteBufferPos, mInByteBuffer.getLength()); std::size_t bytesRemaining = mInByteBuffer.getLength() - mInByteBufferPos; std::size_t bytesToRead = RCF_MIN(bytesRemaining, bytesRequested); ByteBuffer myByteBuffer(mInByteBuffer, mInByteBufferPos, bytesToRead); mInByteBufferPos += bytesToRead; getPreFilter().onReadCompleted(myByteBuffer); }
// -2 for timeout, -1 for error, 0 for peer closure, otherwise size of packet read int timedRecv( BsdClientTransport &clientTransport, I_PollingFunctor &pollingFunctor, int &err, int fd, const ByteBuffer &byteBuffer, std::size_t bytesRequested, int flags) { RCF_ASSERT(!byteBuffer.isEmpty()); std::size_t bytesToRead = RCF_MIN(byteBuffer.getLength(), bytesRequested); while (true) { int ret = Platform::OS::BsdSockets::recv( fd, byteBuffer.getPtr(), static_cast<int>(bytesToRead), flags); err = Platform::OS::BsdSockets::GetLastError(); if (ret >= 0) { err = 0; if (FILE *fp = fopen("c:\\implRead.txt", bytesRequested==4 ? "wb" : "ab")) { fwrite(byteBuffer.getPtr(), byteBuffer.getLength(), 1, fp); fclose(fp); } clientTransport.onTimedRecvCompleted(ret, err); return ret; } else if ( ret == -1 && err == Platform::OS::BsdSockets::ERR_EWOULDBLOCK) { ret = pollingFunctor(fd, err, true); if (ret != 0) { clientTransport.onTimedRecvCompleted(ret, err); return ret; } } else if (ret == -1) { err = Platform::OS::BsdSockets::GetLastError(); clientTransport.onTimedRecvCompleted(-1, err); return -1; } } }
inline void serializeString(SF::Archive & ar, std::basic_string<C,T,A> & s) { if (ar.isRead()) { boost::uint32_t count = 0; ar & count; SF::IStream &is = *ar.getIstream(); s.resize(0); std::size_t minSerializedLength = sizeof(C); if (ar.verifyAgainstArchiveSize(count*minSerializedLength)) { if (count > s.capacity()) { s.reserve(count); } } boost::uint32_t charsRemaining = count; const boost::uint32_t BufferSize = 512; C buffer[BufferSize]; while (charsRemaining) { boost::uint32_t charsToRead = RCF_MIN(BufferSize, charsRemaining); boost::uint32_t bytesToRead = charsToRead*sizeof(C); RCF_VERIFY( is.read( (char *) buffer, bytesToRead) == bytesToRead, RCF::Exception(RCF::_SfError_ReadFailure())) (bytesToRead)(BufferSize)(count); s.append(buffer, charsToRead); charsRemaining -= charsToRead; } } else if (ar.isWrite()) { boost::uint32_t count = static_cast<boost::uint32_t >(s.length()); ar & count; ar.getOstream()->writeRaw( (char *) s.c_str(), count*sizeof(C)); } }
bool PingBackService::cycle( int timeoutMs, const volatile bool &stopFlag) { mTimerHeap.rebase(); PingBackTimerEntry entry; while ( !stopFlag && !mStopFlag && mTimerHeap.popExpiredEntry(entry)) { RcfSessionPtr rcfSessionPtr( entry.second.lock() ); if (rcfSessionPtr) { // No sub-second pingbacks. boost::uint32_t pingBackIntervalMs = rcfSessionPtr->getPingBackIntervalMs(); pingBackIntervalMs = RCF_MAX(pingBackIntervalMs, boost::uint32_t(1000)); boost::uint32_t nextFireMs = Platform::OS::getCurrentTimeMs() + pingBackIntervalMs; Entry nextEntry(nextFireMs, rcfSessionPtr); if ( rcfSessionPtr.get() && rcfSessionPtr->sendPingBack(nextEntry, pingBackIntervalMs)) { mTimerHeap.add(nextEntry); } } } boost::uint32_t queueTimeoutMs = RCF_MIN( static_cast<boost::uint32_t>(timeoutMs), mTimerHeap.getNextEntryTimeoutMs()); if (!stopFlag && !mStopFlag) { Lock lock(mMutex); mCondition.timed_wait(lock, queueTimeoutMs); } return stopFlag || mStopFlag; }
void wait(boost::uint32_t waitMs) { Timer waitTimer; Lock lock(mMutex); while ( !waitTimer.elapsed(waitMs) && mCompletedCount + mFailedCount < mNotifyOnCount) { boost::uint32_t timeUsedSoFarMs = waitTimer.getDurationMs(); timeUsedSoFarMs = RCF_MIN(timeUsedSoFarMs, waitMs); boost::uint32_t timeRemainingMs = waitMs - timeUsedSoFarMs; bool timedOut = mCondition.timed_wait(lock, timeRemainingMs); if ( !timedOut && (mCompletedCount + mFailedCount == mNotifyOnCount)) { break; } } }
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; }
// 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 serializeVectorFastImpl( SF::Archive & ar, I_VecWrapper & vec) { if (ar.isRead()) { boost::uint32_t count = 0; ar & count; if (count) { SF::IStream &is = *ar.getIstream(); vec.resize(0); std::size_t minSerializedLength = vec.sizeofElement(); if (ar.verifyAgainstArchiveSize(count*minSerializedLength)) { // Size field is verified, so read everything in one go. vec.resize(count); boost::uint32_t bytesToRead = count * vec.sizeofElement(); boost::uint32_t bytesActuallyRead = is.read( vec.addressOfElement(0), bytesToRead); RCF_VERIFY( bytesActuallyRead == bytesToRead, RCF::Exception(RCF::_SfError_ReadFailure())) (bytesActuallyRead)(bytesToRead)(count); // Byte ordering. if (ar.getRuntimeVersion() >= 8) { RCF::networkToMachineOrder( vec.addressOfElement(0), static_cast<int>(vec.sizeofElement()), static_cast<int>(vec.size())); } } else { // Size field not verified, so read in chunks. boost::uint32_t elementsRemaining = count; while (elementsRemaining) { const boost::uint32_t ElementsMax = 50*1024; boost::uint32_t elementsRead = count - elementsRemaining; boost::uint32_t elementsToRead = RCF_MIN(ElementsMax, elementsRemaining); boost::uint32_t bytesToRead = elementsToRead*vec.sizeofElement(); vec.resize( vec.size() + elementsToRead); boost::uint32_t bytesRead = is.read( vec.addressOfElement(elementsRead), bytesToRead); RCF_VERIFY( bytesRead == bytesToRead, RCF::Exception(RCF::_SfError_ReadFailure())) (bytesRead)(bytesToRead)(ElementsMax)(count); elementsRemaining -= elementsToRead; } // Byte ordering. if (ar.getRuntimeVersion() >= 8) { RCF::networkToMachineOrder( vec.addressOfElement(0), static_cast<int>(vec.sizeofElement()), static_cast<int>(vec.size())); } } } } else if (ar.isWrite()) { boost::uint32_t count = static_cast<boost::uint32_t>(vec.size()); ar & count; if (count) { boost::uint32_t bytesToWrite = count * vec.sizeofElement(); if (RCF::machineOrderEqualsNetworkOrder()) { // Don't need reordering, so write everything in one go. ar.getOstream()->writeRaw( vec.addressOfElement(0), bytesToWrite); } else if (ar.getRuntimeVersion() < 8) { // Don't need reordering, so write everything in one go. ar.getOstream()->writeRaw( vec.addressOfElement(0), bytesToWrite); } else { // Reordering needed, so we go through a temporary buffer. boost::uint32_t elementsRemaining = count; const boost::uint32_t BufferSize = 100*1024; const boost::uint32_t ElementsMax = BufferSize / vec.sizeofElement(); char Buffer[BufferSize]; while (elementsRemaining) { boost::uint32_t elementsWritten = count - elementsRemaining; boost::uint32_t elementsToWrite = RCF_MIN(ElementsMax, elementsRemaining); boost::uint32_t bytesToWrite = elementsToWrite*vec.sizeofElement(); memcpy( (char *) &Buffer[0], vec.addressOfElement(elementsWritten), bytesToWrite); RCF::machineToNetworkOrder( &Buffer[0], vec.sizeofElement(), elementsToWrite); ar.getOstream()->writeRaw( (char *) &Buffer[0], bytesToWrite); elementsRemaining -= elementsToWrite; } } } } }
void HttpSessionFilter::read( const ByteBuffer &byteBuffer, std::size_t bytesRequested) { if ( mHttpSessionPtr && mWriteBuffers.size() > 0 ) { // If we have a write outstanding, unhook the HTTP session, then write the HTTP response. // When the write completes, another read will be triggered. mHttpSessionPtr->mCachedReadBytesRequested = 0; mHttpSessionPtr->mCachedReadBuffer = ByteBuffer(); if ( bytesRequested ) { mHttpSessionPtr->mCachedReadBytesRequested = bytesRequested; mHttpSessionPtr->mCachedReadBuffer = byteBuffer; } mNetworkSession.getTransportFilters(mHttpSessionPtr->mTransportFilters); mNetworkSession.setTransportFilters(mNoFilters); mNetworkSession.getAsioServerTransport().getServer().detachHttpSession(mHttpSessionPtr); mNetworkSession.mRcfSessionPtr.reset(); mHttpSessionPtr->mRcfSessionPtr->mpNetworkSession = NULL; mHttpSessionPtr.reset(); mpPostFilter->write(mWriteBuffers); } else if ( bytesRequested == 0 ) { // Zero-byte read - pass through to network layer. mpPostFilter->read(byteBuffer, bytesRequested); } else if ( !mHttpSessionPtr ) { // Don't have a HTTP frame yet. Issue a trivial read request on the network layer, // which will force the read of an entire HTTP frame. RCF_ASSERT(bytesRequested > 0); mReadBuffer = ByteBuffer(&mDummy, 1); mpPostFilter->read(mReadBuffer, 1); } else { // HTTP frame is available. Pass reads through to the network layer. if ( mReadBuffer.getLength() > 0 ) { if ( byteBuffer.getLength() > 0 ) { std::size_t bytesToDeliver = RCF_MIN(mReadBuffer.getLength(), bytesRequested); memcpy(byteBuffer.getPtr(), mReadBuffer.getPtr(), bytesToDeliver); mReadBuffer = ByteBuffer(mReadBuffer, bytesToDeliver); mpPreFilter->onReadCompleted(ByteBuffer(byteBuffer, 0, bytesToDeliver)); } else { std::size_t bytesToDeliver = RCF_MIN(mReadBuffer.getLength(), bytesRequested); ByteBuffer buffer(mReadBuffer, 0, bytesToDeliver); mReadBuffer = ByteBuffer(mReadBuffer, bytesToDeliver); mpPreFilter->onReadCompleted(buffer); } } else { mpPostFilter->read(byteBuffer, bytesRequested); } } }