bool PipeConnection::_createPipes() { std::stringstream pipeName; pipeName << "\\\\.\\pipe\\Collage." << UUID( true ); ConnectionDescriptionPtr desc = new ConnectionDescription; desc->type = CONNECTIONTYPE_NAMEDPIPE; desc->setFilename( pipeName.str( )); ConnectionPtr connection = Connection::create( desc ); _namedPipe = static_cast< NamedPipeConnection* >( connection.get( )); if( !_namedPipe->listen( )) return false; _namedPipe->acceptNB(); connection = Connection::create( desc ); _sibling->_namedPipe = static_cast<NamedPipeConnection*>(connection.get()); if( !_sibling->_namedPipe->connect( )) { _sibling->_namedPipe = 0; return false; } connection = _namedPipe->acceptSync(); _namedPipe = static_cast< NamedPipeConnection* >(connection.get( )); return true; }
ConnectionPtr SocketConnection::acceptSync() { LB_TS_THREAD( _recvThread ); if( !isListening( )) return 0; LBASSERT( _overlappedAcceptData ); LBASSERT( _overlappedSocket != INVALID_SOCKET ); if( _overlappedSocket == INVALID_SOCKET ) return 0; // complete accept DWORD got = 0; DWORD flags = 0; if( !WSAGetOverlappedResult( _readFD, &_overlappedRead, &got, TRUE, &flags )) { LBWARN << "Accept completion failed: " << lunchbox::sysError << ", closing socket" << std::endl; close(); return 0; } sockaddr_in* local = 0; sockaddr_in* remote = 0; int localLen = 0; int remoteLen = 0; GetAcceptExSockaddrs( _overlappedAcceptData, 0, sizeof( sockaddr_in ) + 16, sizeof( sockaddr_in ) + 16, (sockaddr**)&local, &localLen, (sockaddr**)&remote, &remoteLen ); _tuneSocket( _overlappedSocket ); ConstConnectionDescriptionPtr description = getDescription(); SocketConnection* newConnection = new SocketConnection; ConnectionPtr connection( newConnection ); // to keep ref-counting correct newConnection->_readFD = _overlappedSocket; newConnection->_writeFD = _overlappedSocket; #ifndef _WIN32 //fcntl( _overlappedSocket, F_SETFL, O_NONBLOCK ); #endif newConnection->_initAIORead(); _overlappedSocket = INVALID_SOCKET; newConnection->_setState( STATE_CONNECTED ); ConnectionDescriptionPtr newDescription = newConnection->_getDescription(); newDescription->bandwidth = description->bandwidth; newDescription->port = ntohs( remote->sin_port ); newDescription->setHostname( getHostName( *remote )); LBDEBUG << "accepted connection from " << newDescription->getHostname() << ":" << newDescription->port << std::endl; return connection; }
void LocalNode::_connectMulticast( NodePtr node ) { EQASSERT( _inReceiverThread( )); base::ScopedMutex<> mutex( _outMulticast ); if( node->_outMulticast.data.isValid( )) // multicast already connected by previous _cmdID return; // Search if the connected node is in the same multicast group as we are ConnectionDescriptions descriptions = getConnectionDescriptions(); for( ConnectionDescriptions::const_iterator i = descriptions.begin(); i != descriptions.end(); ++i ) { ConnectionDescriptionPtr description = *i; if( description->type < CONNECTIONTYPE_MULTICAST ) continue; const ConnectionDescriptions& fromDescs = node->getConnectionDescriptions(); for( ConnectionDescriptions::const_iterator j = fromDescs.begin(); j != fromDescs.end(); ++j ) { ConnectionDescriptionPtr fromDescription = *j; if( !description->isSameMulticastGroup( fromDescription )) continue; EQASSERT( !node->_outMulticast.data ); EQASSERT( node->_multicasts.empty( )); if( _outMulticast->isValid() && _outMulticast.data->getDescription() == description ) { node->_outMulticast.data = _outMulticast.data; EQINFO << "Using " << description << " as multicast group for " << node->getNodeID() << std::endl; } // find unused multicast connection to node else for( MCDatas::const_iterator k = _multicasts.begin(); k != _multicasts.end(); ++k ) { const MCData& data = *k; ConnectionDescriptionPtr dataDesc = data.connection->getDescription(); if( !description->isSameMulticastGroup( dataDesc )) continue; node->_multicasts.push_back( data ); EQINFO << "Adding " << dataDesc << " as multicast group for " << node->getNodeID() << std::endl; } } } }
std::string serialize( const ConnectionDescriptions& descriptions ) { std::ostringstream data; data << descriptions.size() << CO_SEPARATOR; for( ConnectionDescriptions::const_iterator i = descriptions.begin(); i != descriptions.end(); ++i ) { ConnectionDescriptionPtr desc = *i; desc->serialize( data ); } return data.str(); }
// caller: application ConnectionPtr UDTConnection::acceptSync( ) { struct sockaddr address; int addrlen; UDTSOCKET newSocket = UDT::accept( _udt, &address, &addrlen ); UDTConnectionPtr newConnection = new UDTConnection; if( UDT::INVALID_SOCK == newSocket ) { LBERROR << UDTLASTERROR( "UDT::accept" ) << std::endl; close( ); goto err; } acknowledge( _notifier ); newConnection->_udt = newSocket; // Do this after accept, otherwise accept itself becomes non-blocking static const bool OFF = false; if( newConnection->setSockOpt( UDT_RCVSYN, static_cast<const void *>( &OFF ), sizeof(OFF) )) { ConnectionDescriptionPtr desc = newConnection->_getDescription(); desc->setHostname( ::inet_ntoa( ((struct sockaddr_in *)&address)->sin_addr )); desc->port = ntohs( ((struct sockaddr_in *)&address)->sin_port ); desc->bandwidth = getDescription()->bandwidth; if( newConnection->initialize( )) { newConnection->_setState( STATE_CONNECTED ); goto out; } } // else goto err; err: newConnection = 0; out: // Let the event thread continue polling lunchbox::ScopedMutex<> mutex( _app_mutex ); _app_block.set( true ); return newConnection; }
void Connection::_setDescription( ConnectionDescriptionPtr description ) { LBASSERT( description.isValid( )); LBASSERTINFO( _impl->description->type == description->type, "Wrong connection type in description" ); _impl->description = description; LBASSERT( description->bandwidth > 0 ); }
void Connection::setDescription( ConnectionDescriptionPtr description ) { EQASSERT( description.isValid( )); EQASSERTINFO( _description->type == description->type, "Wrong connection type in description" ); _description = description; EQASSERT( description->bandwidth > 0 ); }
std::ostream& operator << ( std::ostream& os, const Connection& connection ) { Connection::State state = connection.getState(); ConnectionDescriptionPtr desc = connection.getDescription(); os << "Connection " << (void*)&connection << " type " << typeid( connection ).name() << " state " << ( state == Connection::STATE_CLOSED ? "closed" : state == Connection::STATE_CONNECTING ? "connecting" : state == Connection::STATE_CONNECTED ? "connected" : state == Connection::STATE_LISTENING ? "listening" : state == Connection::STATE_CLOSING ? "closing" : "UNKNOWN" ); if( desc.isValid( )) os << " description " << desc->toString(); return os; }
bool deserialize( std::string& data, ConnectionDescriptions& descriptions ) { if( !descriptions.empty( )) LBWARN << "Connection descriptions already hold data before deserialize" << std::endl; // num connection descriptions size_t nextPos = data.find( CO_SEPARATOR ); if( nextPos == std::string::npos || nextPos == 0 ) { LBERROR << "Could not parse number of connection descriptions" << std::endl; return false; } const std::string sizeStr = data.substr( 0, nextPos ); if( !isdigit( sizeStr[0] )) { LBERROR << "Could not parse number of connection descriptions" << std::endl; return false; } const size_t nDesc = atoi( sizeStr.c_str( )); data = data.substr( nextPos + 1 ); // connection descriptions for( size_t i = 0; i < nDesc; ++i ) { ConnectionDescriptionPtr desc = new ConnectionDescription; if( !desc->fromString( data )) { LBERROR << "Error during connection description parsing" << std::endl; return false; } descriptions.push_back( desc ); } return true; }
ConnectionPtr SocketConnection::acceptSync() { if( !isListening( )) return 0; sockaddr_in newAddress; socklen_t newAddressLen = sizeof( newAddress ); Socket fd; unsigned nTries = 1000; do fd = ::accept( _readFD, (sockaddr*)&newAddress, &newAddressLen ); while( fd == INVALID_SOCKET && errno == EINTR && --nTries ); if( fd == INVALID_SOCKET ) { LBWARN << "accept failed: " << lunchbox::sysError << std::endl; return 0; } _tuneSocket( fd ); ConstConnectionDescriptionPtr description = getDescription(); SocketConnection* newConnection = new SocketConnection; newConnection->_readFD = fd; newConnection->_writeFD = fd; newConnection->_setState( STATE_CONNECTED ); ConnectionDescriptionPtr newDescription = newConnection->_getDescription(); newDescription->bandwidth = description->bandwidth; newDescription->port = ntohs( newAddress.sin_port ); newDescription->setHostname( inet_ntoa( newAddress.sin_addr )); LBDEBUG << "Accepted " << newDescription->toString() << std::endl; return newConnection; }
//---------------------------------------------------------------------- // listen //---------------------------------------------------------------------- bool SocketConnection::listen() { ConnectionDescriptionPtr description = _getDescription(); LBASSERT( description->type == CONNECTIONTYPE_TCPIP ); if( !isClosed( )) return false; _setState( STATE_CONNECTING ); sockaddr_in address; const size_t size = sizeof( sockaddr_in ); if( !_parseAddress( description, address )) { LBWARN << "Can't parse connection parameters" << std::endl; return false; } if( !_createSocket()) return false; const bool bound = (::bind( _readFD, (sockaddr *)&address, size ) == 0); if( !bound ) { LBWARN << "Could not bind socket " << _readFD << ": " << lunchbox::sysError << " to " << getHostName( address ) << ":" << ntohs( address.sin_port ) << " AF " << (int)address.sin_family << std::endl; close(); return false; } if( ::listen( _readFD, SOMAXCONN ) != 0 ) { LBWARN << "Could not listen on socket: " << lunchbox::sysError << std::endl; close(); return false; } // get socket parameters socklen_t used = size; getsockname( _readFD, (struct sockaddr *)&address, &used ); description->port = ntohs( address.sin_port ); std::string hostname = description->getHostname(); if( hostname.empty( )) { if( address.sin_addr.s_addr == INADDR_ANY ) { char cHostname[256] = {0}; gethostname( cHostname, 256 ); hostname = cHostname; description->setHostname( hostname ); } else description->setHostname( getHostName( address )); } _initAIOAccept(); _setState( STATE_LISTENING ); LBDEBUG << "Listening on " << description->getHostname() << "[" << getHostName( address ) << "]:" << description->port << " (" << description->toString() << ")" << std::endl; return true; }
//---------------------------------------------------------------------- // connect //---------------------------------------------------------------------- bool SocketConnection::connect() { ConnectionDescriptionPtr description = _getDescription(); LBASSERT( description->type == CONNECTIONTYPE_TCPIP ); if( !isClosed( )) return false; if( description->port == 0 ) return false; if( description->getHostname().empty( )) description->setHostname( "127.0.0.1" ); sockaddr_in address; if( !_parseAddress( description, address )) { LBWARN << "Can't parse connection parameters" << std::endl; return false; } _setState( STATE_CONNECTING ); if( !_createSocket( )) return false; if( address.sin_addr.s_addr == 0 ) { LBWARN << "Refuse to connect to 0.0.0.0" << std::endl; close(); return false; } #ifdef _WIN32 const bool connected = WSAConnect( _readFD, (sockaddr*)&address, sizeof( address ), 0, 0, 0, 0 ) == 0; #else int nTries = 10; while( nTries-- ) { const bool connected = (::connect( _readFD, (sockaddr*)&address, sizeof( address )) == 0); if( connected ) break; switch( errno ) { case EINTR: // Happens sometimes, but looks harmless LBDEBUG << "connect: " << lunchbox::sysError << ", retrying" << std::endl; lunchbox::sleep( 5 /*ms*/ ); break; default: nTries = 0; break; } } const bool connected = nTries > 0; #endif if( !connected ) { LBDEBUG << "Could not connect to '" << description->getHostname() << ":" << description->port << "': " << lunchbox::sysError << std::endl; close(); return false; } _initAIORead(); _setState( STATE_CONNECTED ); LBDEBUG << "Connected " << description->toString() << std::endl; return true; }