void ClientStub::onPollingTimeout() { // Check whether we need to fire a client progress timer callback. if (mNextTimerCallbackMs && 0 == generateTimeoutMs(mNextTimerCallbackMs)) { ClientProgress::Action action = ClientProgress::Continue; mClientProgressPtr->mProgressCallback( 0, 0, ClientProgress::Timer, ClientProgress::Receive, action); RCF_VERIFY( action == ClientProgress::Continue, Exception(_RcfError_ClientCancel())) (mTimerIntervalMs); mNextTimerCallbackMs = RCF::getCurrentTimeMs() + mTimerIntervalMs; mNextTimerCallbackMs |= 1; } // Check that pingbacks have been received. if (mNextPingBackCheckMs && 0 == generateTimeoutMs(mNextPingBackCheckMs)) { boost::uint32_t timeNowMs = RCF::getCurrentTimeMs(); boost::uint32_t timeSinceLastPingBackMs = timeNowMs - mPingBackTimeStamp; // Checking for subsequent pingbacks. RCF_VERIFY( timeSinceLastPingBackMs < mPingBackCheckIntervalMs, Exception(_RcfError_PingBackTimeout(mPingBackCheckIntervalMs))) (mPingBackCheckIntervalMs); // Setup polling for next pingback. mPingBackCheckIntervalMs = 3 * mPingBackIntervalMs; mNextPingBackCheckMs = RCF::getCurrentTimeMs() + mPingBackCheckIntervalMs; mNextPingBackCheckMs |= 1; } }
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; }
// return -2 for timeout, -1 for error, 0 for ready int pollSocket(unsigned int endTimeMs, int fd, int &err, bool bRead) { ClientStub & clientStub = *getTlsClientStubPtr(); while (true) { fd_set fdSet; FD_ZERO(&fdSet); FD_SET( static_cast<SOCKET>(fd), &fdSet); unsigned int timeoutMs = generateTimeoutMs(endTimeMs); timeoutMs = clientStub.generatePollingTimeout(timeoutMs); timeval timeout = {0}; timeout.tv_sec = timeoutMs/1000; timeout.tv_usec = 1000*(timeoutMs%1000); RCF_ASSERT_GTEQ(timeout.tv_usec , 0); int selectRet = bRead ? Platform::OS::BsdSockets::select(fd+1, &fdSet, NULL, NULL, &timeout) : Platform::OS::BsdSockets::select(fd+1, NULL, &fdSet, NULL, &timeout); err = Platform::OS::BsdSockets::GetLastError(); // Handle timeout. if (selectRet == 0) { clientStub.onPollingTimeout(); if (generateTimeoutMs(endTimeMs) != 0) { continue; } } // Some socket gymnastics to determine whether a nonblocking connect // has failed or not. if (selectRet == 1 && !bRead) { int errorOpt = 0; Platform::OS::BsdSockets::socklen_t len = sizeof(int); int ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)(&errorOpt), &len); err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( ret == 0, Exception(_RcfError_Socket("getsockopt()"), err, RcfSubsystem_Os)); if (errorOpt == 0) { return 0; } else if ( errorOpt == Platform::OS::BsdSockets::ERR_EWOULDBLOCK || errorOpt == Platform::OS::BsdSockets::ERR_EINPROGRESS) { continue; } else { err = errorOpt; return -1; } } switch (selectRet) { case 0: return -2; case 1: return 0; default: return -1; }; } }
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); } } }