Future<TransportSocketPtr> TransportSocketCache::socket(const ServiceInfo& servInfo, const std::string& protocol) { const std::string& machineId = servInfo.machineId(); ConnectionAttemptPtr couple = boost::make_shared<ConnectionAttempt>(); couple->relatedUrls = servInfo.endpoints(); bool local = machineId == os::getMachineId(); UrlVector connectionCandidates; // If the connection is local, we're mainly interested in localhost endpoint if (local) connectionCandidates = localhost_only(servInfo.endpoints()); // If the connection isn't local or if the service doesn't expose local endpoints, // try and connect to whatever is available. if (connectionCandidates.size() == 0) connectionCandidates = servInfo.endpoints(); couple->endpoint = TransportSocketPtr(); couple->state = State_Pending; { // If we already have a pending connection to one of the urls, we return the future in question boost::mutex::scoped_lock lock(_socketMutex); if (_dying) return makeFutureError<TransportSocketPtr>("TransportSocketCache is closed."); ConnectionMap::iterator machineIt = _connections.find(machineId); if (machineIt != _connections.end()) { // Check if any connection to the machine matches one of our urls UrlVector& vurls = couple->relatedUrls; for (std::map<Url, ConnectionAttemptPtr>::iterator b = machineIt->second.begin(), e = machineIt->second.end(); b != e; b++) { UrlVector::iterator uIt = std::find(vurls.begin(), vurls.end(), b->first); // We found a matching machineId and URL : return the connected endpoint. if (uIt != vurls.end()) return b->second->promise.future(); } } // Otherwise, we keep track of all those URLs and assign them the same promise in our map. // They will all track the same connection. couple->attemptCount = connectionCandidates.size(); std::map<Url, ConnectionAttemptPtr>& urlMap = _connections[machineId]; for (UrlVector::iterator it = connectionCandidates.begin(), end = connectionCandidates.end(); it != end; ++it) { urlMap[*it] = couple; TransportSocketPtr socket = makeTransportSocket(it->protocol()); _allPendingConnections.push_back(socket); Future<void> sockFuture = socket->connect(*it); qiLogDebug() << "Inserted [" << machineId << "][" << it->str() << "]"; sockFuture.connect(&TransportSocketCache::onSocketParallelConnectionAttempt, this, _1, socket, *it, servInfo); } } return couple->promise.future(); }
static UrlVector localhost_only(const UrlVector& input) { UrlVector result; result.reserve(input.size()); for (const auto& url: input) { if (isLocalHost(url.host())) result.push_back(url); } return result; }
static UrlVector localhost_only(const UrlVector& input) { UrlVector result; result.reserve(input.size()); for (UrlVector::const_iterator it = input.begin(), end = input.end(); it != end; ++it) { const std::string& host = it->host(); if (boost::algorithm::starts_with(host, "127.") || host == "localhost") result.push_back(*it); } return result; }