std::pair<std::string, std::vector<std::string> > getLocalIps() { std::vector<char> hostname(80); int ret = gethostname(&hostname[0], static_cast<int>(hostname.size())); int err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( ret != -1, RCF::Exception( _RcfError_Socket("gethostname()"), err, RcfSubsystem_Os))(ret); hostent *phe = gethostbyname(&hostname[0]); err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( phe, RCF::Exception( _RcfError_Socket("gethostbyname()"), err, RCF::RcfSubsystem_Os)); std::vector<std::string> ips; for (int i = 0; phe->h_addr_list[i] != 0; ++i) { struct in_addr addr; memcpy(&addr, phe->h_addr_list[i], sizeof( in_addr)); ips.push_back(inet_ntoa(addr)); } return std::make_pair( std::string(&hostname[0]), ips); }
void initWinsock() { WORD wVersion = MAKEWORD( 1, 0 ); WSADATA wsaData; int ret = WSAStartup(wVersion, &wsaData); int err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY(ret == 0, Exception( _RcfError_Socket("WSAStartup()"), err, RcfSubsystem_Os) ); }
void discardPacket(int fd) { char buffer[1]; int len = recvfrom(fd, buffer, 1, 0, NULL, NULL); int err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( len == 1 || (len == -1 && err == Platform::OS::BsdSockets::ERR_EMSGSIZE) || (len == -1 && err == Platform::OS::BsdSockets::ERR_ECONNRESET), Exception( _RcfError_Socket("recvfrom()"), err, RcfSubsystem_Os)); }
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 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; }
void UnixLocalClientTransport::implClose() { if (mFd != -1) { int ret = Platform::OS::BsdSockets::closesocket(mFd); int err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( ret == 0, Exception( _RcfError_Socket(), err, RcfSubsystem_Os, "closesocket() failed")) (mFd); } mFd = -1; }
// 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; }; } }
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 UdpServerTransport::cycle(int timeoutMs) { RCF::ThreadInfoPtr tiPtr = getTlsThreadInfoPtr(); RCF::ThreadPool & threadPool = tiPtr->getThreadPool(); if (threadPool.shouldStop()) { return; } // poll the UDP socket for messages, and read a message if one is available fd_set fdSet; FD_ZERO(&fdSet); FD_SET( static_cast<SOCKET>(mFd), &fdSet); timeval timeout; timeout.tv_sec = timeoutMs/1000; timeout.tv_usec = 1000*(timeoutMs%1000); int ret = Platform::OS::BsdSockets::select( mFd+1, &fdSet, NULL, NULL, timeoutMs < 0 ? NULL : &timeout); int err = Platform::OS::BsdSockets::GetLastError(); if (ret == 1) { SessionStatePtr sessionStatePtr = getTlsUdpSessionStatePtr(); if (sessionStatePtr.get() == NULL) { sessionStatePtr = SessionStatePtr(new SessionState(*this)); sessionStatePtr->mSessionPtr = getSessionManager().createSession(); sessionStatePtr->mSessionPtr->setSessionState(*sessionStatePtr); setTlsUdpSessionStatePtr(sessionStatePtr); } { // read a message ReallocBufferPtr &readVecPtr = sessionStatePtr->mReadVecPtr; if (readVecPtr.get() == NULL || !readVecPtr.unique()) { readVecPtr.reset( new ReallocBuffer()); } ReallocBuffer &buffer = *readVecPtr; SockAddrStorage from; int fromlen = sizeof(from); memset(&from, 0, sizeof(from)); buffer.resize(4); int len = Platform::OS::BsdSockets::recvfrom( mFd, &buffer[0], 4, MSG_PEEK, (sockaddr *) &from, &fromlen); err = Platform::OS::BsdSockets::GetLastError(); sessionStatePtr->mRemoteAddress.init( (sockaddr&) from, fromlen, mIpAddress.getType()); if (!isIpAllowed(sessionStatePtr->mRemoteAddress)) { RCF_LOG_2()(sessionStatePtr->mRemoteAddress.getIp()) << "Client IP does not match server's IP access rules. Closing connection."; discardPacket(mFd); } else if ( len == 4 || (len == -1 && err == Platform::OS::BsdSockets::ERR_EMSGSIZE)) { unsigned int dataLength = 0; memcpy(&dataLength, &buffer[0], 4); networkToMachineOrder(&dataLength, 4, 1); if (getMaxMessageLength() && dataLength > getMaxMessageLength()) { ByteBuffer byteBuffer; encodeServerError(getSessionManager(), byteBuffer, RcfError_ServerMessageLength); byteBuffer.expandIntoLeftMargin(4); * (boost::uint32_t *) ( byteBuffer.getPtr() ) = static_cast<boost::uint32_t>(byteBuffer.getLength()-4); RCF::machineToNetworkOrder(byteBuffer.getPtr(), 4, 1); char *buffer = byteBuffer.getPtr(); std::size_t bufferLen = byteBuffer.getLength(); sockaddr * pRemoteAddr = NULL; Platform::OS::BsdSockets::socklen_t remoteAddrSize = 0; sessionStatePtr->mRemoteAddress.getSockAddr(pRemoteAddr, remoteAddrSize); int len = sendto( mFd, buffer, static_cast<int>(bufferLen), 0, pRemoteAddr, remoteAddrSize); RCF_UNUSED_VARIABLE(len); discardPacket(mFd); } else { buffer.resize(4+dataLength); memset(&from, 0, sizeof(from)); fromlen = sizeof(from); len = Platform::OS::BsdSockets::recvfrom( mFd, &buffer[0], 4+dataLength, 0, (sockaddr *) &from, &fromlen); if (static_cast<unsigned int>(len) == 4+dataLength) { getSessionManager().onReadCompleted(sessionStatePtr->mSessionPtr); } } } else { discardPacket(mFd); } } } else if (ret == 0) { //RCF_LOG_4()(mFd)(mPort)(timeoutMs) << "UdpServerTransport - no messages received within polling interval."; } else if (ret == -1) { Exception e( _RcfError_Socket("select()"), err, RcfSubsystem_Os); RCF_THROW(e)(mFd)(mIpAddress.string())(err); } }
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); } } }
{ m_hIOCP = NULL; Create(nMaxConcurrency); } Iocp::~Iocp() { RCF_DTOR_BEGIN if (m_hIOCP != NULL) { int ret = CloseHandle(m_hIOCP); int err = Platform::OS::BsdSockets::GetLastError(); RCF_VERIFY( ret, Exception( _RcfError_Socket(), err, RcfSubsystem_Os, "CloseHande() failed")) (m_hIOCP); } RCF_DTOR_END } void Iocp::Create(int nMaxConcurrency) { m_hIOCP = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, 0, nMaxConcurrency);