void Win32NamedPipeNetworkSession::implWrite(const std::vector<ByteBuffer> & buffers) { if ( !mSocketPtr ) { RCF_LOG_4() << "Win32NamedPipeNetworkSession - connection has been closed."; return; } RCF_LOG_4()(RCF::lengthByteBuffers(buffers)) << "Win32NamedPipeNetworkSession - calling WriteFile()."; ASIO_NS::windows::overlapped_ptr overlapped( mSocketPtr->get_io_service(), WriteHandler(sharedFromThis())); const ByteBuffer & byteBuffer = buffers.front(); DWORD dwBytesWritten = 0; bool writeOk = false; HANDLE hPipe = mSocketPtr->native(); BOOL ok = WriteFile( hPipe, byteBuffer.getPtr(), static_cast<DWORD>(byteBuffer.getLength()), &dwBytesWritten, overlapped.get()); DWORD dwErr = GetLastError();; if (!ok && ( dwErr == ERROR_IO_PENDING || dwErr == ERROR_MORE_DATA)) { writeOk = true; } else if (dwBytesWritten) { writeOk = true; } if (writeOk) { overlapped.release(); } else { AsioErrorCode ec( dwErr, ASIO_NS::error::get_system_category()); overlapped.complete(ec, 0); } }
void FileIoRequest::complete() { RCF_LOG_4() << "FileIoRequest::complete() - entry"; RCF::Lock lock(mFts.mCompletionMutex); while (!mCompleted) { mFts.mCompletionCondition.timed_wait(lock, 1000); } mInitiated = false; RCF_LOG_4() << "FileIoRequest::complete() - exit"; }
AsioSessionState::~AsioSessionState() { RCF_DTOR_BEGIN // TODO: invoke accept if appropriate // TODO: need a proper acceptex strategy in the first place //RCF_ASSERT(mState != Accepting); mTransport.unregisterSession(mWeakThisPtr); RCF_LOG_4()(mState)(mSessionPtr.get())(mSessionPtr->mDisableIo) << "AsioSessionState - destructor."; // close reflecting session if appropriate if (mReflecting) { AsioSessionStatePtr sessionStatePtr(mReflecteeWeakPtr.lock()); if (sessionStatePtr) { sessionStatePtr->close(); } } RCF_DTOR_END; }
bool FileIoRequest::isInitiated() { RCF_LOG_4() << "FileIoRequest::isInitiated()"; RCF::Lock lock(mFts.mCompletionMutex); return mInitiated; }
bool FileIoRequest::completed() { RCF_LOG_4() << "FileIoRequest::completed"; RCF::Lock lock(mFts.mCompletionMutex); return mCompleted; }
FileIoRequest::FileIoRequest() : mFts( getFileIoThreadPool() ), mBytesTransferred(0), mInitiated(false), mCompleted(true) { RCF_LOG_4() << "FileIoRequest::FileIoRequest"; }
void AsioSessionState::onNetworkReadCompleted( AsioErrorCode error, size_t bytesTransferred) { RCF_LOG_4()(this)(bytesTransferred) << "AsioSessionState - read from socket completed."; ThreadTouchGuard threadTouchGuard; mLastError = error; mBytesReceivedCounter += bytesTransferred; #ifdef BOOST_WINDOWS if (error.value() == ERROR_OPERATION_ABORTED) { error = AsioErrorCode(); } #endif if (!error && !mTransport.mStopFlag) { if (bytesTransferred == 0 && mIssueZeroByteRead) { // TCP framing. if (!mAppReadBufferPtr || !mAppReadBufferPtr.unique()) { mAppReadBufferPtr = getObjectPool().getReallocBufferPtr(); } mAppReadBufferPtr->resize(4); mReadBufferRemaining = 4; mIssueZeroByteRead = false; beginRead(); } else if (mReflecting) { AsioErrorCode ec; onReflectedReadWriteCompleted(ec, bytesTransferred); } else { CurrentRcfSessionSentry guard(*mSessionPtr); mNetworkReadByteBuffer = ByteBuffer( mNetworkReadByteBuffer, 0, bytesTransferred); mTransportFilters.empty() ? onAppReadWriteCompleted(bytesTransferred) : mTransportFilters.back()->onReadCompleted(mNetworkReadByteBuffer); } } }
void FileIoRequest::complete() { RCF_LOG_4() << "FileIoRequest::complete()"; RCF::Lock lock(mFts.mCompletionMutex); while (!mCompleted) { mFts.mCompletionCondition.wait(lock); } mInitiated = false; }
void FileIoRequest::doTransfer() { if (mFinPtr) { RCF_LOG_4() << "FileIoRequest::doTransfer() - initiate read."; char * szBuffer = mBuffer.getPtr(); std::size_t szBufferLen = mBuffer.getLength(); mFinPtr->read(szBuffer, szBufferLen); mBytesTransferred = mFinPtr->gcount(); mFinPtr.reset(); RCF_LOG_4()(mBytesTransferred) << "FileIoRequest::doTransfer() - read complete."; } else if (mFoutPtr) { RCF_LOG_4() << "FileIoRequest::doTransfer() - initiate write."; char * szBuffer = mBuffer.getPtr(); std::size_t szBufferLen = mBuffer.getLength(); boost::uint64_t pos0 = mFoutPtr->tellp(); mFoutPtr->write(szBuffer, szBufferLen); boost::uint64_t pos1 = mFoutPtr->tellp(); RCF_ASSERT_GTEQ(pos1 , pos0); mBytesTransferred = pos1 - pos0; RCF_ASSERT_EQ(mBytesTransferred , szBufferLen); mFoutPtr.reset(); RCF_LOG_4()(mBytesTransferred) << "FileIoRequest::doTransfer() - write complete."; } else { RCF_ASSERT(0); mBytesTransferred = 0; } }
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 Win32NamedPipeNetworkSession::implAccept() { RCF_LOG_4()<< "Win32NamedPipeNetworkSession - calling ConnectNamedPipe()."; ASIO_NS::windows::overlapped_ptr overlapped( mSocketPtr->get_io_service(), boost::bind( &AsioNetworkSession::onAcceptCompleted, sharedFromThis(), ASIO_NS::placeholders::error)); HANDLE hPipe = mSocketPtr->native(); BOOL ok = ConnectNamedPipe(hPipe, overlapped.get()); DWORD dwErr = GetLastError(); // ConnectNamedPipe() can complete either synchronously or // asynchronously. We need to cater for both possibilities. if ( !ok && dwErr == ERROR_IO_PENDING ) { // Asynchronous accept. overlapped.release(); } else if (!ok && dwErr == ERROR_PIPE_CONNECTED) { // Synchronous connect. AsioErrorCode ec; overlapped.complete(ec, 0); } else { // ConnectNamedPipe() may return a synchronous error. In particular we sometimes // get ERROR_NO_DATA ("The pipe is being closed"). So, here we need another // accept call. // MSDN says ConectNamedPipe will always return 0, in overlapped mode. RCF_ASSERT(!ok); mTransport.createNetworkSession()->beginAccept(); } }
void AsioSessionState::onNetworkWriteCompleted( AsioErrorCode error, size_t bytesTransferred) { RCF_LOG_4()(this)(bytesTransferred) << "AsioSessionState - write to socket completed."; ThreadTouchGuard threadTouchGuard; mLastError = error; mBytesSentCounter += bytesTransferred; #ifdef BOOST_WINDOWS if (error.value() == ERROR_OPERATION_ABORTED) { error = AsioErrorCode(); } #endif if (!error && !mTransport.mStopFlag) { if (mReflecting) { if (mReflecteePtr) { mReflecteePtr.reset(); } AsioErrorCode ec; onReflectedReadWriteCompleted(ec, bytesTransferred); } else { CurrentRcfSessionSentry guard(*mSessionPtr); mTransportFilters.empty() ? onAppReadWriteCompleted(bytesTransferred) : mTransportFilters.back()->onWriteCompleted(bytesTransferred); } } }
void FileIoRequest::write(boost::shared_ptr<std::ofstream> foutPtr, RCF::ByteBuffer buffer) { RCF_LOG_4()(foutPtr.get())((void*)buffer.getPtr())(buffer.getLength()) << "FileIoRequest::write()"; mFinPtr.reset(); mFoutPtr = foutPtr; mBuffer = buffer; mBytesTransferred = 0; mInitiated = true; mCompleted = false; mFts.registerOp( shared_from_this() ); // For debugging purposes, we can wait in this function until the file I/O is completed. if (mFts.mSerializeFileIo) { RCF::Lock lock(mFts.mCompletionMutex); while (!mCompleted) { mFts.mCompletionCondition.wait(lock); } } }
boost::uint64_t FileIoRequest::getBytesTransferred() { RCF_LOG_4()(mBytesTransferred) << "FileIoRequest::getBytesTransferred()"; return mBytesTransferred; }
FileIoRequest::~FileIoRequest() { RCF_LOG_4() << "FileIoRequest::~FileIoRequest"; }
void UdpServerTransport::open() { RCF_LOG_4()(mIpAddress.string()) << "UdpServerTransport - creating server socket."; int mPort = mIpAddress.getPort(); // create and bind a socket for receiving UDP messages if (mFd == -1 && mPort >= 0) { int ret = 0; int err = 0; mIpAddress.resolve(); mFd = mIpAddress.createSocket(SOCK_DGRAM, IPPROTO_UDP); // enable reception of broadcast messages int enable = 1; ret = setsockopt(mFd, SOL_SOCKET, SO_BROADCAST, (char *) &enable, sizeof(enable)); err = Platform::OS::BsdSockets::GetLastError(); if (ret) { RCF_LOG_1()(ret)(err) << "setsockopt() - failed to set SO_BROADCAST on listening udp socket."; } // Share the address binding, if appropriate. if (mEnableSharedAddressBinding) { enable = 1; // Set SO_REUSEADDR socket option. ret = setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, (char *) &enable, sizeof(enable)); err = Platform::OS::BsdSockets::GetLastError(); if (ret) { RCF_LOG_1()(ret)(err) << "setsockopt() - failed to set SO_REUSEADDR on listening udp multicast socket."; } // On OS X and BSD variants, need to set SO_REUSEPORT as well. #if (defined(__MACH__) && defined(__APPLE__)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) ret = setsockopt(mFd, SOL_SOCKET, SO_REUSEPORT, (char *) &enable, sizeof(enable)); err = Platform::OS::BsdSockets::GetLastError(); if (ret) { RCF_LOG_1()(ret)(err) << "setsockopt() - failed to set SO_REUSEPORT on listening udp multicast socket."; } #endif } sockaddr * pServerAddr = NULL; Platform::OS::BsdSockets::socklen_t serverAddrSize = 0; mIpAddress.getSockAddr(pServerAddr, serverAddrSize); // bind the socket ret = ::bind(mFd, pServerAddr, serverAddrSize); if (ret < 0) { err = Platform::OS::BsdSockets::GetLastError(); Exception e(_RcfError_Socket("bind()"), err, RcfSubsystem_Os); RCF_THROW(e)(mFd)(mIpAddress.string())(ret); } RCF_ASSERT_NEQ( mFd , -1 ); if (!mMulticastIpAddress.empty()) { // set socket option for receiving multicast messages mMulticastIpAddress.resolve(); // TODO: implement for IPv6. RCF_ASSERT( mIpAddress.getType() == IpAddress::V4 && mMulticastIpAddress.getType() == IpAddress::V4); std::string ip = mMulticastIpAddress.getIp(); ip_mreq imr; imr.imr_multiaddr.s_addr = inet_addr(ip.c_str()); imr.imr_interface.s_addr = INADDR_ANY; int ret = setsockopt(mFd,IPPROTO_IP, IP_ADD_MEMBERSHIP, (const char*) &imr, sizeof(imr)); int err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( ret == 0, Exception( _RcfError_Socket("setsockopt() with IPPROTO_IP/IP_ADD_MEMBERSHIP"), err, RcfSubsystem_Os)) (mMulticastIpAddress.string())(mIpAddress.string()); // TODO: enable source-filtered multicast messages //ip_mreq_source imr; //imr.imr_multiaddr.s_addr = inet_addr("232.5.6.7"); //imr.imr_sourceaddr.s_addr = INADDR_ANY;//inet_addr("10.1.1.2"); //imr.imr_interface.s_addr = INADDR_ANY; //int ret = setsockopt(mFd,IPPROTO_IP, IP_ADD_SOURCE_MEMBERSHIP, (const char*) &imr, sizeof(imr)); //int err = Platform::OS::BsdSockets::GetLastError(); } // set the socket to nonblocking mode Platform::OS::BsdSockets::setblocking(mFd, false); // retrieve the port number, if it's generated by the system if (mPort == 0) { IpAddress ip(mFd, mIpAddress.getType()); mPort = ip.getPort(); mIpAddress.setPort(mPort); } RCF_LOG_2() << "UdpServerTransport - listening on port " << mPort << "."; } }
void Win32NamedPipeNetworkSession::implRead(char * buffer, std::size_t bufferLen) { if ( !mSocketPtr ) { RCF_LOG_4() << "Win32NamedPipeNetworkSession - connection has been closed."; return; } RCF_LOG_4()(bufferLen) << "Win32NamedPipeNetworkSession - calling ReadFile()."; ASIO_NS::windows::overlapped_ptr overlapped( mSocketPtr->get_io_service(), ReadHandler(sharedFromThis())); DWORD dwBytesRead = 0; bool readOk = false; HANDLE hPipe = mSocketPtr->native(); BOOL ok = ReadFile( hPipe, buffer, static_cast<DWORD>(bufferLen), &dwBytesRead, overlapped.get()); DWORD realError = 0; DWORD dwErr = 0; if (!ok) { dwErr = GetLastError(); if ( dwErr != ERROR_IO_PENDING && dwErr != ERROR_MORE_DATA) { realError = dwErr; } } if ( dwBytesRead || (ok && dwBytesRead == 0 && bufferLen == 0) || (!ok && realError == 0)) { readOk = true; } if (readOk) { overlapped.release(); } else { AsioErrorCode ec( dwErr, ASIO_NS::error::get_system_category()); overlapped.complete(ec, 0); } }
void UdpClientTransport::connect( I_ClientTransportCallback &clientStub, unsigned int timeoutMs) { RCF_LOG_4()(mSock)(mDestIp.string()) << "UdpClientTransport - creating socket."; RCF_UNUSED_VARIABLE(timeoutMs); RCF_ASSERT(!mAsync); // TODO: replace throw with return value if (mSock == -1) { int ret = 0; int err = 0; // remote address mDestIp.resolve(); // local address if (mLocalIp.empty()) { std::string localIp = mDestIp.getType() == IpAddress::V4 ? "0.0.0.0" : "::0" ; mSrcIp = IpAddress(localIp, 0); } else { mSrcIp = mLocalIp; } mSrcIp.resolve(); mSock = mSrcIp.createSocket(SOCK_DGRAM, IPPROTO_UDP); sockaddr * pSrcAddr = NULL; Platform::OS::BsdSockets::socklen_t srcAddrSize = 0; mSrcIp.getSockAddr(pSrcAddr, srcAddrSize); ret = ::bind(mSock, pSrcAddr, srcAddrSize); err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( ret == 0, Exception( _RcfError_Socket("bind()"), err, RcfSubsystem_Os)); mAssignedLocalIp = IpAddress(mSock, mSrcIp.getType()); #if defined(BOOST_WINDOWS) && defined(SIO_UDP_CONNRESET) // On Windows XP and later, disable the SIO_UDP_CONNRESET socket option. BOOL enable = FALSE; DWORD dwBytesRet = 0; DWORD dwStatus = WSAIoctl(mSock, SIO_UDP_CONNRESET, &enable, sizeof(enable), NULL, 0, &dwBytesRet, NULL, NULL); err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( dwStatus == 0, Exception( _RcfError_Socket("WSAIoctl() with SIO_UDP_CONNRESET"), err, RcfSubsystem_Os)); #endif // BOOST_WINDOWS if (mDestIp.isBroadcast()) { // set socket option to allow transmission of broadcast messages int enable = 1; int ret = setsockopt(mSock, SOL_SOCKET, SO_BROADCAST, (char *) &enable, sizeof(enable)); int err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( ret == 0, Exception( _RcfError_Socket("setsockopt() with SO_BROADCAST"), err, RcfSubsystem_Os)); } if (mDestIp.isMulticast()) { // char for Solaris, int for everyone else. #if defined(__SVR4) && defined(__sun) char hops = 16; #else int hops = 16; #endif int ret = setsockopt(mSock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &hops, sizeof (hops)); int err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( ret == 0, Exception( _RcfError_Socket("setsockopt() with IPPROTO_IP/IP_MULTICAST_TTL"), err, RcfSubsystem_Os))(hops); } } clientStub.onConnectCompleted(); }
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); } } }
void AsioSessionState::onAcceptCompleted( const AsioErrorCode & error) { RCF_LOG_4()(error.value()) << "AsioSessionState - onAccept()."; if (mTransport.mStopFlag) { RCF_LOG_4()(error.value()) << "AsioSessionState - onAccept(). Returning early, stop flag is set."; return; } //if ( // error == ASIO_NS::error::connection_aborted || // error == ASIO_NS::error::operation_aborted) //{ // beginAccept(); // return; //} // create a new SessionState, and do an accept on that mTransport.createSessionState()->beginAccept(); if (!error) { // save the remote address in the SessionState object bool clientAddrAllowed = implOnAccept(); mState = WritingData; // set current RCF session CurrentRcfSessionSentry guard(*mSessionPtr); mSessionPtr->touch(); if (clientAddrAllowed) { // Check the connection limit. bool allowConnect = true; std::size_t connectionLimit = mTransport.getConnectionLimit(); if (connectionLimit) { Lock lock(mTransport.mSessionsMutex); RCF_ASSERT_LTEQ( mTransport.mSessions.size() , 1+1+connectionLimit); if (mTransport.mSessions.size() == 1+1+connectionLimit) { allowConnect = false; } } if (allowConnect) { time_t now = 0; now = time(NULL); mSessionPtr->setConnectedAtTime(now); // start things rolling by faking a completed write operation onAppReadWriteCompleted(0); } else { sendServerError(RcfError_ConnectionLimitExceeded); } } } }