void MenuManager::AppendServicesMenu(ITSMenu& mnu, ItemTypeEnum it) { PrgAPI* pAPI = PRGAPI(); ServicesRegistrationSrv* pSRS = pAPI->GetServicesRegistrationSrv(); INT added = 0; for (INT i = 0; i < (INT)pSRS->GetServicesCount(); i++) { ServiceTypeEnum st = STYPE_Unknown; switch (it) { case IT_Artist: st = STYPE_ArtistInfo; break; case IT_Album: st = STYPE_AlbumInfo; break; case IT_Track: st = STYPE_TrackInfo; break; default: ASSERT(0); break; } ServiceInfo si; if (pSRS->GetServiceInfo(i, si) && si.CanHandle(st)) { if ((added-1) % 5 == 0 && added > 1) mnu.AppendMenu(ITSMenu::MIT_Separator, 0, 0); added++; mnu.AppendMenu(ITSMenu::MIT_String, MENU_WebServicesHolder + i, (LPTSTR)si.Name, si.hIcon); } } }
void Device::connectToService(const QString &uuid) { QLowEnergyService *service = 0; for (int i = 0; i < m_services.size(); i++) { ServiceInfo *serviceInfo = (ServiceInfo*)m_services.at(i); if (serviceInfo->getUuid() == uuid) { service = serviceInfo->service(); break; } } if (!service) return; qDeleteAll(m_characteristics); m_characteristics.clear(); emit characteristicsUpdated(); if (service->state() == QLowEnergyService::DiscoveryRequired) { //! [les-service-3] connect(service, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(serviceDetailsDiscovered(QLowEnergyService::ServiceState))); service->discoverDetails(); setUpdate("Back\n(Discovering details...)"); //! [les-service-3] return; } //discovery already done const QList<QLowEnergyCharacteristic> chars = service->characteristics(); foreach (const QLowEnergyCharacteristic &ch, chars) { CharacteristicInfo *cInfo = new CharacteristicInfo(ch); m_characteristics.append(cInfo); }
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(); }
void Session_SD::updateServiceInfo() { ServiceInfo si; si.setName("ServiceDirectory"); si.setServiceId(qi::Message::Service_ServiceDirectory); si.setMachineId(qi::os::getMachineId()); si.setEndpoints(_server->endpoints()); _sdObject->updateServiceInfo(si); }
void TransportSocketCache::onSocketDisconnected(Url url, const ServiceInfo& info) { // remove from the available connections boost::mutex::scoped_lock lock(_socketMutex); ConnectionMap::iterator machineIt = _connections.find(info.machineId()); if (machineIt == _connections.end()) return; qiLogDebug() << "onSocketDisconnected: about to erase socket"; auto attempt = machineIt->second[url]; attempt->state = State_Error; checkClear(attempt, info.machineId()); auto syncDisconnectInfos = _disconnectInfos.synchronize(); updateDisconnectInfos(*syncDisconnectInfos, attempt->endpoint); }
void TransportSocketCache::onSocketDisconnected(TransportSocketPtr socket, Url url, const std::string& reason, const ServiceInfo& info) { // remove from the available connections boost::mutex::scoped_lock lock(_socketMutex); ConnectionMap::iterator machineIt = _connections.find(info.machineId()); if (machineIt == _connections.end()) return; machineIt->second[url]->state = State_Error; checkClear(machineIt->second[url], info.machineId()); }
void TransportSocketCache::insert(const std::string& machineId, const Url& url, MessageSocketPtr socket) { // If a connection is pending for this machine / url, terminate the pendage and set the // service socket as this one boost::mutex::scoped_lock lock(_socketMutex); if (_dying) return; ServiceInfo info; info.setMachineId(machineId); qi::SignalLink disconnectionTracking = socket->disconnected.connect( &TransportSocketCache::onSocketDisconnected, this, url, info) .setCallType(MetaCallType_Direct); ConnectionMap::iterator mIt = _connections.find(machineId); if (mIt != _connections.end()) { std::map<Url, ConnectionAttemptPtr>::iterator uIt = mIt->second.find(url); if (uIt != mIt->second.end()) { auto& connectionAttempt = *uIt->second; QI_ASSERT(!connectionAttempt.endpoint); // If the attempt is done and the endpoint is null, it means the // attempt failed and the promise is set as error. // We replace it by a new one. // If the attempt is not done we do not replace it, otherwise the future // currently in circulation will never finish. if (connectionAttempt.state != State_Pending) connectionAttempt.promise = Promise<MessageSocketPtr>(); connectionAttempt.state = State_Connected; connectionAttempt.endpoint = socket; connectionAttempt.promise.setValue(socket); connectionAttempt.disconnectionTracking = disconnectionTracking; return; } } ConnectionAttemptPtr couple = boost::make_shared<ConnectionAttempt>(); couple->promise = Promise<MessageSocketPtr>(); couple->endpoint = socket; couple->state = State_Connected; couple->relatedUrls.push_back(url); _connections[machineId][url] = couple; couple->promise.setValue(socket); }
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()); }
qi::Future<void> Session_SD::listenStandalone(const qi::Url &address) { if (_init) throw std::runtime_error("Already initialised"); _init = true; _server->addObject(1, _serviceBoundObject); qiLogInfo() << "ServiceDirectory listener created on " << address.str(); qi::Future<void> f = _server->listen(address); std::map<unsigned int, ServiceInfo>::iterator it = _sdObject->connectedServices.find(qi::Message::Service_ServiceDirectory); if (it != _sdObject->connectedServices.end()) { it->second.setEndpoints(_server->endpoints()); return f; } ServiceInfo si; si.setName("ServiceDirectory"); si.setServiceId(qi::Message::Service_ServiceDirectory); si.setMachineId(qi::os::getMachineId()); si.setProcessId(qi::os::getpid()); si.setSessionId("0"); si.setEndpoints(_server->endpoints()); unsigned int regid = _sdObject->registerService(si); (void)regid; _sdObject->serviceReady(qi::Message::Service_ServiceDirectory); //serviceDirectory must have id '1' assert(regid == qi::Message::Service_ServiceDirectory); _server->_server.endpointsChanged.connect(boost::bind(&Session_SD::updateServiceInfo, this)); return f; }
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 PeerInfo::deserialize(InputStream& inputStream) throw (SerializationException&) { inputStream.read_ulong(m_type); UUID* peerID = new UUID(inputStream); m_uuidPtr.reset(peerID); UUID* fID = new UUID(inputStream); m_fidPtr.reset(fID); Boolean flag = false; inputStream.read_boolean(flag); if (flag) { SAPInfo* e = new SAPInfo(inputStream); m_meshSAP.reset(e); } else { m_meshSAP.reset(0); } inputStream.read_boolean(flag); if (flag) { SAPInfo* e = new SAPInfo(inputStream); m_discoverySAP.reset(e); } else { m_discoverySAP.reset(0); } inputStream.read_boolean(flag); if (flag) { SAPInfo* e = new SAPInfo(inputStream); m_ftSAP.reset(e); } else { m_ftSAP.reset(0); } //services m_serviceMap.unbind_all(); int count = 0; inputStream.read_long(count); for (int i = 0; i < count; i++) { ServiceInfo* pi = new ServiceInfo(inputStream); ServiceInfoPtr iPtr(pi); m_serviceMap.bind(pi->getSid(), iPtr); } }
extern "C" int main(int ac, char **av) { MPI::init(ac,av); MPI::Group world(MPI_COMM_WORLD); std::string portName = ""; std::vector<std::string> nonDashArgs; for (int i=1;i<ac;i++) { const std::string arg = av[i]; if (arg[0] == '-') { throw std::runtime_error("unknown arg "+arg); } else nonDashArgs.push_back(arg); } if (nonDashArgs.size() != 2) { cout << "Usage: ./ospDwTest <hostName> <portNo>" << endl; exit(1); } const std::string hostName = nonDashArgs[0]; const int portNum = atoi(nonDashArgs[1].c_str()); ServiceInfo serviceInfo; serviceInfo.getFrom(hostName,portNum); // ------------------------------------------------------- // args parsed, now do the job // ------------------------------------------------------- MPI::Group me = world.dup(); Client *client = new Client(me,serviceInfo.mpiPortName); while (1) renderFrame(me,client); return 0; }
qi::Future<void> Session_SD::listenStandalone(const std::vector<qi::Url> &listenAddresses) { if (_init) throw std::runtime_error("Already initialised"); _init = true; _server->addObject(1, _serviceBoundObject); std::ostringstream messInfo; messInfo << "ServiceDirectory listener created on"; qi::FutureBarrier<void> barrier; for (const qi::Url& url : listenAddresses) { messInfo << " " << url.str(); barrier.addFuture(_server->listen(url)); } qiLogInfo() << messInfo.str(); qi::Promise<void> prom; qi::adaptFuture(barrier.future(), prom); qi::Future<void> f = prom.future(); std::map<unsigned int, ServiceInfo>::iterator it = _sdObject->connectedServices.find(qi::Message::Service_ServiceDirectory); if (it != _sdObject->connectedServices.end()) { it->second.setEndpoints(_server->endpoints()); return f; } ServiceInfo si; si.setName("ServiceDirectory"); si.setServiceId(qi::Message::Service_ServiceDirectory); si.setMachineId(qi::os::getMachineId()); si.setProcessId(qi::os::getpid()); si.setSessionId("0"); si.setEndpoints(_server->endpoints()); unsigned int regid = _sdObject->registerService(si); (void)regid; _sdObject->serviceReady(qi::Message::Service_ServiceDirectory); //serviceDirectory must have id '1' QI_ASSERT(regid == qi::Message::Service_ServiceDirectory); _server->_server.endpointsChanged.connect(boost::bind(&Session_SD::updateServiceInfo, this)); return f; }
am_status_t BaseService::doRequest(const ServiceInfo& service, const BodyChunk& headerPrefix, const std::string& uriParameters, const Http::CookieList& cookieList, const BodyChunk& headerSuffix, const BodyChunkList& bodyChunkList, Http::Response& response, std::size_t initialBufferLen, const std::string &cert_nick_name, const ServerInfo** serverInfo) const { am_status_t status = AM_SERVICE_NOT_AVAILABLE; std::size_t dataLen = 0; // Create a temporary buffer for the Content-Line header // the extra '2' is for the <CR><LF> at the end. The // sizeof the CONTENT_LENGTH_HDR includes space for the // terminating NUL. char contentLine[sizeof(CONTENT_LENGTH_HDR) + (sizeof(dataLen) * DIGITS_PER_BYTE) + 2]; std::size_t contentLineLen; for (unsigned int i = 0; i < bodyChunkList.size(); ++i) { dataLen += bodyChunkList[i].data.size(); } contentLineLen = snprintf(contentLine, sizeof(contentLine), "%s%d\r\n", CONTENT_LENGTH_HDR, dataLen); if (sizeof(contentLine) > contentLineLen) { BodyChunk contentLineChunk(contentLine, contentLineLen); ServiceInfo::const_iterator iter; for (iter = service.begin(); iter != service.end(); ++iter) { ServerInfo svrInfo = ServerInfo((const ServerInfo&)(*iter)); if (!svrInfo.isHealthy(poll_primary_server)) { Log::log(logModule, Log::LOG_WARNING, "BaseService::doRequest(): " "Server is unavailable: %s.", svrInfo.getURL().c_str()); continue; } else { Log::log(logModule, Log::LOG_DEBUG, "BaseService::doRequest(): Using server: %s.", iter->getURL().c_str()); } Http::HeaderList headerList, proxyHeaderList; Http::Cookie hostHeader("Host", svrInfo.getHost()); headerList.push_back(hostHeader); if (useProxy) { proxyHeaderList.push_back(hostHeader); // Override (temporarily) server credentials if using proxy svrInfo.setHost(proxyHost); svrInfo.setPort(proxyPort); // We don't use SSL for initial proxy connection svrInfo.setUseSSL(false); Log::log(logModule, Log::LOG_DEBUG, "BaseService::doRequest(): Using proxy: %s:%d", proxyHost.c_str(),proxyPort); // Add Proxy-Authorization header if user defined if (useProxyAuth) { // allocate enough for a base64-encoded digest int authSize = proxyUser.size() + proxyPassword.size() + 1; // 11 extra bytes for prefix and terminator char * digest = (char *)malloc(authSize * 4/3 + 11); strcpy(digest, "Basic "); encode_base64((proxyUser + ":" + proxyPassword).c_str(), authSize,(digest + 6)); Log::log(logModule, Log::LOG_MAX_DEBUG, "BaseService::doRequest(): Using proxy auth as: %s", proxyUser.c_str()); hostHeader = Http::Cookie("Proxy-Authorization", digest); proxyHeaderList.push_back(hostHeader); free(digest); } } // retry to connect to server before marking it as down. // making the number of attempts configurable may have a negative // side effect on performance, if the the value is a high number. int retryAttempts = 3; int retryCount = 0; while(retryCount < retryAttempts) { retryCount++; try { Connection conn(svrInfo, certDBPasswd, (cert_nick_name.size()>0)?cert_nick_name:certNickName, alwaysTrustServerCert); const char *operation = "sending to"; // in case proxy is defined and target URL is HTTPS, // establish an SSL tunnel first send // CONNECT host:port string if (useProxy && iter->useSSL()) { SECStatus secStatus = SECFailure; // All the other parameters would be empty for a // proxy CONNECT Http::CookieList emptyCookieList; BodyChunk emptyChunk; BodyChunkList emptyChunkList; // Add a Keep-alive header since we're using HTTP/1.0 hostHeader = Http::Cookie("Connection", "Keep-Alive\r\n"); proxyHeaderList.push_back(hostHeader); status = sendRequest(conn, BodyChunk(std::string("CONNECT ")), iter->getHost() + ":" + Utils::toString(iter->getPort()), std::string(""), proxyHeaderList, emptyCookieList, emptyChunk, emptyChunk, emptyChunkList); if (status == AM_SUCCESS) { // Retrieve proxie's response if tunnel // established (void) response.readAndIgnore(logModule, conn); // Secure the tunnel now by upgrading the socket PRFileDesc *sock = conn.secureSocket( certDBPasswd, (cert_nick_name.size()>0)? cert_nick_name:certNickName, alwaysTrustServerCert, NULL); if (sock != static_cast<PRFileDesc *>(NULL)) { secStatus = SSL_SetURL(sock, iter->getHost().c_str()); } } if (status != AM_SUCCESS || SECSuccess != secStatus){ Log::log(logModule, Log::LOG_ERROR, "BaseService::doRequest(): could not " "establish a secure proxy tunnel"); // Can't continue and mark server as down as // it was a proxy failure return AM_FAILURE; } } if(Log::isLevelEnabled(logModule, Log::LOG_MAX_DEBUG)) { std::string commString; for(std::size_t i = 0; i<bodyChunkList.size(); ++i) { if(!bodyChunkList[i].secure) { commString.append(bodyChunkList[i].data); } else { commString.append("<secure data>"); } } for(std::size_t commPos = commString.find("%"); commPos != std::string::npos && commPos < commString.size(); commPos = commString.find("%", commPos)) { commString.replace(commPos, 1, "%%"); commPos += 2; } Log::log(logModule, Log::LOG_MAX_DEBUG, commString.c_str()); } std::string requestString = iter->getURI(); /* * In case the following request would go to a proxy * we need to use full URL and special headers. * If the resource is HTTPS, we're not posting our * request to the proxy, but to the server * through proxy tunnel */ if (useProxy && !(iter->useSSL())) { requestString = iter->getURL(); headerList = proxyHeaderList; } status = sendRequest(conn, headerPrefix, requestString, uriParameters, headerList, cookieList, contentLineChunk, headerSuffix, bodyChunkList); if (AM_SUCCESS == status) { operation = "receiving from"; status = response.readAndParse(logModule, conn, initialBufferLen); if (AM_SUCCESS == status) { Log::log(logModule, Log::LOG_MAX_DEBUG, "%.*s", response.getBodyLen(), response.getBodyPtr()); } } if (AM_NSPR_ERROR == status) { PRErrorCode nspr_code = PR_GetError(); Log::log(logModule, Log::LOG_ALWAYS, "BaseService::doRequest() NSPR failure while " "%s %s, error = %s", operation, (*iter).toString().c_str(), PR_ErrorToName(nspr_code)); } if (AM_SUCCESS == status) { if(serverInfo != NULL) *serverInfo = &(*iter); break; } else { if(retryCount < retryAttempts) { continue; } else { Log::log(logModule, Log::LOG_DEBUG, "BaseService::doRequest() Invoking markSeverDown"); svrInfo.markServerDown(poll_primary_server); } } } catch (const NSPRException& exc) { Log::log(logModule, Log::LOG_DEBUG, "BaseService::doRequest() caught %s: %s called by %s " "returned %s", exc.what(), exc.getNsprMethod(), exc.getThrowingMethod(), PR_ErrorToName(exc.getErrorCode())); if(retryCount < retryAttempts) { status = AM_NSPR_ERROR; continue; } else { Log::log(logModule, Log::LOG_DEBUG, "BaseService::doRequest() Invoking markSeverDown"); svrInfo.markServerDown(poll_primary_server); status = AM_NSPR_ERROR; } } } //end of while if (AM_SUCCESS == status) { if(serverInfo != NULL) *serverInfo = &(*iter); break; } if (status = AM_NSPR_ERROR) { continue; } } // end of for } else { status = AM_BUFFER_TOO_SMALL; } return status; }
BOOL WebPane::OnButton(UINT idx) { if (idx >= MENU_WebServicesHolder && idx < MENU_WebServicesHolderEnd) { PrgAPI* pAPI = PRGAPI(); ServicesRegistrationSrv* pSRS = pAPI->GetServicesRegistrationSrv(); ServiceInfo si; INT serviceID = idx - MENU_WebServicesHolder; if (pSRS->GetServiceInfo(serviceID, si)) { if (si.CanHandle(STYPE_ArtistInfo)) { if (m_SyncWithArtistService == serviceID) m_SyncWithArtistService = -1; else m_SyncWithArtistService = serviceID; } else if (si.CanHandle(STYPE_AlbumInfo)) { if (m_SyncWithAlbumService == serviceID) m_SyncWithAlbumService = -1; else m_SyncWithAlbumService = serviceID; } else if (si.CanHandle(STYPE_TrackInfo)) { if (m_SyncWithTrackService == serviceID) m_SyncWithTrackService = -1; else m_SyncWithTrackService = serviceID; } else ASSERT(0); } return TRUE; } else { switch (idx) { case MI_SyncWithPlayer: m_bSyncWithPlayer = !m_bSyncWithPlayer; break; case MI_SyncWithSectionChanger: m_bSyncWithSectionsChanger= !m_bSyncWithSectionsChanger; break; case MI_SyncWithTracksChanger: m_bSyncWithTracksChanger = !m_bSyncWithTracksChanger; break; case MI_UseAsWebViewer: { ServicesRegistrationSrv* pSRS = PRGAPI()->GetServicesRegistrationSrv(); ServicesRegistrationSrv::IWebViewer* pViewer = pSRS->GetWebViewer(); if (pViewer != this) pSRS->SetWebViewer(this); else pSRS->SetWebViewer(NULL); } break; default: ASSERT(0); return FALSE; } } return TRUE; }
/* * Corner case to manage (TODO): * * You are connecting to machineId foo, you are machineId bar. foo and bar are * on different sub-networks with the same netmask. They sadly got the same IP * on their subnet: 192.168.1.42. When trying to connect to foo from bar, we * will try to connect its endpoints, basically: * - tcp://1.2.3.4:1333 (public IP) * - tcp://192.168.1.42:1333 (subnet public IP) * If bar is listening on port 1333, we may connect to it instead of foo (our * real target). */ void TransportSocketCache::onSocketParallelConnectionAttempt(Future<void> fut, MessageSocketPtr socket, Url url, const ServiceInfo& info) { boost::mutex::scoped_lock lock(_socketMutex); if (_dying) { qiLogDebug() << "ConnectionAttempt: TransportSocketCache is closed"; if (!fut.hasError()) { _allPendingConnections.remove(socket); socket->disconnect(); } return; } ConnectionMap::iterator machineIt = _connections.find(info.machineId()); std::map<Url, ConnectionAttemptPtr>::iterator urlIt; if (machineIt != _connections.end()) urlIt = machineIt->second.find(url); if (machineIt == _connections.end() || urlIt == machineIt->second.end()) { // The socket was disconnected at some point, and we removed it from our map: // return early. _allPendingConnections.remove(socket); socket->disconnect(); return; } ConnectionAttemptPtr attempt = urlIt->second; attempt->attemptCount--; if (attempt->state != State_Pending) { qiLogDebug() << "Already connected: reject socket " << socket.get() << " endpoint " << url.str(); _allPendingConnections.remove(socket); socket->disconnect(); checkClear(attempt, info.machineId()); return; } if (fut.hasError()) { // Failing to connect to some of the endpoint is expected. qiLogDebug() << "Could not connect to service #" << info.serviceId() << " through url " << url.str(); _allPendingConnections.remove(socket); // It's a critical error if we've exhausted all available endpoints. if (attempt->attemptCount == 0) { std::stringstream err; err << "Could not connect to service #" << info.serviceId() << ": no endpoint replied."; qiLogError() << err.str(); attempt->promise.setError(err.str()); attempt->state = State_Error; checkClear(attempt, info.machineId()); } return; } qi::SignalLink disconnectionTracking = socket->disconnected.connect( &TransportSocketCache::onSocketDisconnected, this, url, info) .setCallType(MetaCallType_Direct); attempt->state = State_Connected; attempt->endpoint = socket; attempt->promise.setValue(socket); attempt->disconnectionTracking = disconnectionTracking; qiLogDebug() << "Connected to service #" << info.serviceId() << " through url " << url.str() << " and socket " << socket.get(); }