GwTransaction(const Message& msg) : content(msg) , _destination(TransportSocketPtr()) , _originalObjectId(msg.object()) , _originalServiceId(msg.service()) { }
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(); }
qi::TransportSocketPtr ServiceDirectory::_socketOfService(unsigned int id) { boost::recursive_mutex::scoped_lock lock(mutex); std::map<unsigned int, TransportSocketPtr>::iterator it = idxToSocket.find(id); if (it == idxToSocket.end()) return TransportSocketPtr(); else return it->second; }
void GwObjectHost::assignClientMessageObjectsGwIds(const Signature& signature, Message& msg, TransportSocketPtr sender) { // if there's no chance of any object being in the call we're done. if (!hasObjectsSomewhere(signature)) return; AnyReference callParameters = msg.value(signature, sender); // re-serialize the arguments so that the objects can receive a GW-specific objectId // ObjectHost uses a static int for its objectId so we're OK instantiating multiple // ones. Message forward; MockObjectHost host(Message::Service_Server); forward.setFlags(msg.flags()); forward.setValue(callParameters, signature, &host, sender.get()); msg.setBuffer(forward.buffer()); // The message will store all the objects it serializes in the host. const ObjectHost::ObjectMap& objects = host.objects(); std::map<GwObjectId, MetaObject> newObjectsMetaObjects; std::map<GwObjectId, std::pair<TransportSocketPtr, ObjectAddress> > newObjectsOrigin; std::map<ObjectAddress, GwObjectId> newHostObjectBank; for (ObjectHost::ObjectMap::const_iterator it = objects.begin(), end = objects.end(); it != end; ++it) { GwObjectId oid = it->first; ServiceBoundObject* sbo = static_cast<ServiceBoundObject*>(it->second.get()); RemoteObject* ro = static_cast<RemoteObject*>(sbo->object().asGenericObject()->value); ObjectAddress addr; addr.service = ro->service(); addr.object = ro->object(); ro->setTransportSocket(TransportSocketPtr()); newObjectsMetaObjects[oid] = ro->metaObject(); newObjectsOrigin[oid] = std::make_pair(sender, addr); newHostObjectBank[addr] = oid; // We set an empty transportsocket. // Otherwise when we destroy `passed` below, the remoteobject // will attempt to send back home a `terminate` message, which we don't want. // By setting a null socket the object will stay alive on the remote end. qiLogDebug() << "Message " << msg.address() << ", Object connection: {" << addr.service << "," << addr.object << "} <=> {0," << oid << "}"; } { boost::upgrade_lock<boost::shared_mutex> lock(_mutex); boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock); _objectsMetaObjects.insert(newObjectsMetaObjects.begin(), newObjectsMetaObjects.end()); _objectsOrigin.insert(newObjectsOrigin.begin(), newObjectsOrigin.end()); _hostObjectBank[sender].insert(newHostObjectBank.begin(), newHostObjectBank.end()); } callParameters.destroy(); }
void GwObjectHost::harvestServiceOriginatingObjects(Message& msg, TransportSocketPtr sender) { Signature signature; { boost::upgrade_lock<boost::shared_mutex> lock(_mutex); MetaObject* metaObject = NULL; const Signature& (MetaMethod::*signatureGetter)() const = NULL; if (msg.type() == Message::Type_Reply || msg.type() == Message::Type_Error) { std::map<ServiceId, std::map<ObjectId, MetaObject> >::iterator sit = _servicesMetaObjects.find(msg.service()); if (msg.function() == Message::BoundObjectFunction_MetaObject && sit->second.find(msg.object()) == sit->second.end()) { boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock); _servicesMetaObjects[msg.service()][Message::GenericObject_Main] = extractReturnedMetaObject(msg, sender); return; } metaObject = &_servicesMetaObjects[msg.service()][msg.object()]; signatureGetter = &MetaMethod::returnSignature; } else if (msg.type() == Message::Type_Call || msg.type() == Message::Type_Post) { // if a service does a CALL, he does so on a user-supplied object. std::map<GwObjectId, MetaObject>::iterator mit = _objectsMetaObjects.find(msg.object()); assert(mit != _objectsMetaObjects.end()); metaObject = &mit->second; signatureGetter = &MetaMethod::parametersSignature; } const MetaMethod* method = metaObject->method(msg.function()); if (!method) return; signature = (method->*signatureGetter)(); } if (!hasObjectsSomewhere(signature)) { // no object can be here return; } AnyReference passed = msg.value(signature, sender); StreamContext filler; MockObjectHost host(Message::Service_Server); Message dummy; // we don't want to pollute the original message and potentially change valid id // of contained objects, so we do it in an unrelated message. dummy.setValue(passed, signature, &host, &filler); const ObjectHost::ObjectMap& objects = host.objects(); std::map<ObjectId, MetaObject> newServicesMetaObject; for (ObjectHost::ObjectMap::const_iterator it = objects.begin(), end = objects.end(); it != end; ++it) { ServiceBoundObject* sbo = static_cast<ServiceBoundObject*>(it->second.get()); RemoteObject* ro = static_cast<RemoteObject*>(sbo->object().asGenericObject()->value); // We set an empty transportsocket. // Otherwise when we destroy `passed` below, the remoteobject // will attempt to send back home a `terminate` message, which we don't want. // By setting a null socket the object will stay alive on the remote end. ro->setTransportSocket(TransportSocketPtr()); newServicesMetaObject[ro->object()] = ro->metaObject(); } { boost::upgrade_lock<boost::shared_mutex> lock(_mutex); boost::upgrade_to_unique_lock<boost::shared_mutex> unique_lock(lock); _servicesMetaObjects[msg.service()].insert(newServicesMetaObject.begin(), newServicesMetaObject.end()); } passed.destroy(); }