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(); }
unsigned int ServiceDirectory::registerService(const ServiceInfo &svcinfo) { boost::shared_ptr<ServiceBoundObject> sbo = serviceBoundObject.lock(); if (!sbo) throw std::runtime_error("ServiceBoundObject has expired."); TransportSocketPtr socket = sbo->currentSocket(); boost::recursive_mutex::scoped_lock lock(mutex); std::map<std::string, unsigned int>::iterator it; it = nameToIdx.find(svcinfo.name()); if (it != nameToIdx.end()) { std::stringstream ss; ss << "Service \"" << svcinfo.name() << "\" (#" << it->second << ") is already registered. " << "Rejecting conflicting registration attempt."; qiLogWarning() << ss.str(); throw std::runtime_error(ss.str()); } unsigned int idx = ++servicesCount; nameToIdx[svcinfo.name()] = idx; // Do not add serviceDirectory on the map (socket() == null) if (idx != qi::Message::Service_ServiceDirectory) socketToIdx[socket].push_back(idx); pendingServices[idx] = svcinfo; pendingServices[idx].setServiceId(idx); idxToSocket[idx] = socket; std::stringstream ss; ss << "Registered Service \"" << svcinfo.name() << "\" (#" << idx << ")"; if (! svcinfo.name().empty() && svcinfo.name()[0] == '_') { // Hide services whose name starts with an underscore qiLogDebug() << ss.str(); } else { qiLogInfo() << ss.str(); } qi::UrlVector::const_iterator jt; for (jt = svcinfo.endpoints().begin(); jt != svcinfo.endpoints().end(); ++jt) { qiLogDebug() << "Service \"" << svcinfo.name() << "\" is now on " << jt->str(); } return idx; }
void ServiceDirectory::updateServiceInfo(const ServiceInfo &svcinfo) { boost::recursive_mutex::scoped_lock lock(mutex); std::map<unsigned int, ServiceInfo>::iterator itService; for (itService = connectedServices.begin(); itService != connectedServices.end(); ++itService) { if (svcinfo.sessionId() == itService->second.sessionId()) { itService->second.setEndpoints(svcinfo.endpoints()); } } itService = connectedServices.find(svcinfo.serviceId()); if (itService != connectedServices.end()) { connectedServices[svcinfo.serviceId()] = svcinfo; return; } // maybe the service registration was pending... itService = pendingServices.find(svcinfo.serviceId()); if (itService != pendingServices.end()) { pendingServices[svcinfo.serviceId()] = svcinfo; return; } std::stringstream ss; ss << "updateServiceInfo: Can't find service #" << svcinfo.serviceId(); qiLogVerbose() << ss.str(); throw std::runtime_error(ss.str()); }