void SessionPrivate::addSdSocketToCache(Future<void> f, const qi::Url& url, qi::Promise<void> p) { qiLogDebug() << "addSocketToCache processing"; if (f.hasError()) { qiLogDebug() << "addSdSocketToCache: connect reported failure"; _serviceHandler.removeService("ServiceDirectory"); p.setError(f.error()); return; } // Allow the SD process to use the existing socket to talk to our services _serverObject.registerSocket(_sdClient.socket()); /* Allow reusing the SD socket for communicating with services. * To do this, we must add it to our socket cache, and for this we need * to know the sd machineId */ std::string mid; try { mid = _sdClient.machineId(); } catch (const std::exception& e) { // Provide a nice message for backward compatibility qiLogVerbose() << e.what(); qiLogWarning() << "Failed to obtain machineId, connection to service directory will not be reused for other services."; p.setValue(0); return; } TransportSocketPtr s = _sdClient.socket(); qiLogVerbose() << "Inserting sd to cache for " << mid <<" " << url.str() << std::endl; _socketsCache.insert(mid, s->remoteEndpoint(), s); p.setValue(0); }
/* * 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(); }