diff options
Diffstat (limited to 'cpp/src/Ice/Reference.cpp')
-rw-r--r-- | cpp/src/Ice/Reference.cpp | 1960 |
1 files changed, 1960 insertions, 0 deletions
diff --git a/cpp/src/Ice/Reference.cpp b/cpp/src/Ice/Reference.cpp new file mode 100644 index 00000000000..875b64ebe53 --- /dev/null +++ b/cpp/src/Ice/Reference.cpp @@ -0,0 +1,1960 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <Ice/Reference.h> +#include <Ice/ReferenceFactory.h> +#include <Ice/LocalException.h> +#include <Ice/Instance.h> +#include <Ice/EndpointI.h> +#include <Ice/OpaqueEndpointI.h> +#include <Ice/BasicStream.h> +#include <Ice/RouterInfo.h> +#include <Ice/Router.h> +#include <Ice/LocatorInfo.h> +#include <Ice/Locator.h> +#include <Ice/Functional.h> +#include <Ice/ConnectionI.h> +#include <Ice/ConnectionFactory.h> +#include <Ice/LoggerUtil.h> +#include <Ice/TraceLevels.h> +#include <Ice/HashUtil.h> +#include <Ice/DefaultsAndOverrides.h> +#include <IceUtil/StringUtil.h> +#include <IceUtil/Random.h> +#include <IceUtil/MutexPtrLock.h> + +#include <functional> + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +IceUtil::Shared* IceInternal::upCast(IceInternal::Reference* p) { return p; } + +namespace +{ + +IceUtil::Mutex* hashMutex = 0; + +class Init +{ +public: + + Init() + { + hashMutex = new IceUtil::Mutex; + } + + ~Init() + { + delete hashMutex; + hashMutex = 0; + } +}; + +Init init; + +struct RandomNumberGenerator : public std::unary_function<ptrdiff_t, ptrdiff_t> +{ + ptrdiff_t operator()(ptrdiff_t d) + { + return IceUtilInternal::random(static_cast<int>(d)); + } +}; + +} + +CommunicatorPtr +IceInternal::Reference::getCommunicator() const +{ + return _communicator; +} + +ReferencePtr +IceInternal::Reference::changeContext(const Context& newContext) const +{ + ReferencePtr r = _instance->referenceFactory()->copy(this); + r->_context = new SharedContext(newContext); + return r; +} + +ReferencePtr +IceInternal::Reference::changeMode(Mode newMode) const +{ + if(newMode == _mode) + { + return ReferencePtr(const_cast<Reference*>(this)); + } + ReferencePtr r = _instance->referenceFactory()->copy(this); + r->_mode = newMode; + return r; +} + +ReferencePtr +IceInternal::Reference::changeSecure(bool newSecure) const +{ + if(newSecure == _secure) + { + return ReferencePtr(const_cast<Reference*>(this)); + } + ReferencePtr r = _instance->referenceFactory()->copy(this); + r->_secure = newSecure; + return r; +} + +ReferencePtr +IceInternal::Reference::changeIdentity(const Identity& newIdentity) const +{ + if(newIdentity == _identity) + { + return ReferencePtr(const_cast<Reference*>(this)); + } + ReferencePtr r = _instance->referenceFactory()->copy(this); + r->_identity = newIdentity; + return r; +} + +ReferencePtr +IceInternal::Reference::changeFacet(const string& newFacet) const +{ + if(newFacet == _facet) + { + return ReferencePtr(const_cast<Reference*>(this)); + } + ReferencePtr r = _instance->referenceFactory()->copy(this); + r->_facet = newFacet; + return r; +} + +ReferencePtr +IceInternal::Reference::changeCompress(bool newCompress) const +{ + if(_overrideCompress && newCompress == _compress) + { + return ReferencePtr(const_cast<Reference*>(this)); + } + ReferencePtr r = _instance->referenceFactory()->copy(this); + r->_compress = newCompress; + r->_overrideCompress = true; + return r; +} + +Int +Reference::hash() const +{ + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(hashMutex); + if(!_hashInitialized) + { + _hashValue = hashInit(); + _hashInitialized = true; + } + return _hashValue; +} + +void +IceInternal::Reference::streamWrite(BasicStream* s) const +{ + // + // Don't write the identity here. Operations calling streamWrite + // write the identity. + // + + // + // For compatibility with the old FacetPath. + // + if(_facet.empty()) + { + s->write(static_cast<string*>(0), static_cast<string*>(0)); + } + else + { + s->write(&_facet, &_facet + 1); + } + + s->write(static_cast<Byte>(_mode)); + + s->write(_secure); + + // Derived class writes the remainder of the reference. +} + +string +IceInternal::Reference::toString() const +{ + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + ostringstream s; + + // + // If the encoded identity string contains characters which + // the reference parser uses as separators, then we enclose + // the identity string in quotes. + // + string id = _instance->identityToString(_identity); + if(id.find_first_of(" :@") != string::npos) + { + s << '"' << id << '"'; + } + else + { + s << id; + } + + if(!_facet.empty()) + { + s << " -f "; + + // + // If the encoded facet string contains characters which + // the reference parser uses as separators, then we enclose + // the facet string in quotes. + // + string fs = Ice::nativeToUTF8(_instance->initializationData().stringConverter, _facet); + fs = IceUtilInternal::escapeString(fs, ""); + if(fs.find_first_of(" :@") != string::npos) + { + s << '"' << fs << '"'; + } + else + { + s << fs; + } + } + + switch(_mode) + { + case ModeTwoway: + { + s << " -t"; + break; + } + + case ModeOneway: + { + s << " -o"; + break; + } + + case ModeBatchOneway: + { + s << " -O"; + break; + } + + case ModeDatagram: + { + s << " -d"; + break; + } + + case ModeBatchDatagram: + { + s << " -D"; + break; + } + } + + if(_secure) + { + s << " -s"; + } + + return s.str(); + + // Derived class writes the remainder of the string. +} + +bool +IceInternal::Reference::operator==(const Reference& r) const +{ + // + // Note: if(this == &r) test is performed by each non-abstract derived class. + // + + if(_mode != r._mode) + { + return false; + } + + if(_secure != r._secure) + { + return false; + } + + if(_identity != r._identity) + { + return false; + } + + if(_context->getValue() != r._context->getValue()) + { + return false; + } + + if(_facet != r._facet) + { + return false; + } + + if((_overrideCompress != r._overrideCompress) || (_overrideCompress && _compress != r._compress)) + { + return false; + } + + return true; +} + +bool +IceInternal::Reference::operator!=(const Reference& r) const +{ + return !operator==(r); +} + +bool +IceInternal::Reference::operator<(const Reference& r) const +{ + // + // Note: if(this == &r) test is performed by each non-abstract derived class. + // + + if(_mode < r._mode) + { + return true; + } + else if(r._mode < _mode) + { + return false; + } + + if(_identity < r._identity) + { + return true; + } + else if(r._identity < _identity) + { + return false; + } + + if(_context->getValue() < r._context->getValue()) + { + return true; + } + else if(r._context->getValue() < _context->getValue()) + { + return false; + } + + if(_facet < r._facet) + { + return true; + } + else if(r._facet < _facet) + { + return false; + } + + if(!_overrideCompress && r._overrideCompress) + { + return true; + } + else if(r._overrideCompress < _overrideCompress) + { + return false; + } + else if(_overrideCompress) + { + if(!_compress && r._compress) + { + return true; + } + else if(r._compress < _compress) + { + return false; + } + } + + if(!_secure && r._secure) + { + return true; + } + else if(r._secure < _secure) + { + return false; + } + + return false; +} + +class ConnectionIsDatagram : public unary_function<ConnectionIPtr, bool> +{ +public: + + bool + operator()(ConnectionIPtr p) const + { + return p->endpoint()->datagram(); + } +}; + +class ConnectionIsSecure : public unary_function<ConnectionIPtr, bool> +{ +public: + + bool + operator()(ConnectionIPtr p) const + { + return p->endpoint()->secure(); + } +}; + +IceInternal::Reference::Reference(const InstancePtr& instance, + const CommunicatorPtr& communicator, + const Identity& id, + const string& facet, + Mode mode, + bool secure) : + _hashInitialized(false), + _instance(instance), + _communicator(communicator), + _mode(mode), + _secure(secure), + _identity(id), + _context(new SharedContext), + _facet(facet), + _overrideCompress(false), + _compress(false) +{ +} + +IceInternal::Reference::Reference(const Reference& r) : + _hashInitialized(false), + _instance(r._instance), + _communicator(r._communicator), + _mode(r._mode), + _secure(r._secure), + _identity(r._identity), + _context(r._context), + _facet(r._facet), + _overrideCompress(r._overrideCompress), + _compress(r._compress) +{ +} + +int +IceInternal::Reference::hashInit() const +{ + Int h = static_cast<Int>(_mode); + hashAdd(h, _identity.name); + hashAdd(h, _identity.category); + hashAdd(h, _context->getValue()); + hashAdd(h, _facet); + hashAdd(h, _secure); + return h; +} + +IceUtil::Shared* IceInternal::upCast(IceInternal::FixedReference* p) { return p; } + +IceInternal::FixedReference::FixedReference(const InstancePtr& instance, + const CommunicatorPtr& communicator, + const Identity& id, + const string& facet, + Mode mode, + bool secure, + const ConnectionIPtr& fixedConnection) : + Reference(instance, communicator, id, facet, mode, secure), + _fixedConnection(fixedConnection) +{ +} + +vector<EndpointIPtr> +IceInternal::FixedReference::getEndpoints() const +{ + return vector<EndpointIPtr>(); +} + +string +IceInternal::FixedReference::getAdapterId() const +{ + return string(); +} + +bool +IceInternal::FixedReference::getCollocationOptimized() const +{ + return false; +} + +bool +IceInternal::FixedReference::getCacheConnection() const +{ + return false; +} + +bool +IceInternal::FixedReference::getPreferSecure() const +{ + return false; +} + +Ice::EndpointSelectionType +IceInternal::FixedReference::getEndpointSelection() const +{ + return Random; +} + +int +IceInternal::FixedReference::getLocatorCacheTimeout() const +{ + return 0; +} + +string +IceInternal::FixedReference::getConnectionId() const +{ + return string(); +} + +ReferencePtr +IceInternal::FixedReference::changeEndpoints(const vector<EndpointIPtr>& newEndpoints) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeAdapterId(const string& newAdapterId) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeLocator(const LocatorPrx&) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeRouter(const RouterPrx&) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeCollocationOptimized(bool) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeCacheConnection(bool) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changePreferSecure(bool) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeEndpointSelection(EndpointSelectionType) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeLocatorCacheTimeout(int) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeTimeout(int) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +ReferencePtr +IceInternal::FixedReference::changeConnectionId(const string&) const +{ + throw FixedProxyException(__FILE__, __LINE__); + return 0; // Keep the compiler happy. +} + +bool +IceInternal::FixedReference::isIndirect() const +{ + return false; +} + +bool +IceInternal::FixedReference::isWellKnown() const +{ + return false; +} + +void +IceInternal::FixedReference::streamWrite(BasicStream* s) const +{ + throw FixedProxyException(__FILE__, __LINE__); +} + +string +IceInternal::FixedReference::toString() const +{ + throw FixedProxyException(__FILE__, __LINE__); + + assert(false); // Cannot be reached. + return string(); // To keep the compiler from complaining. +} + +PropertyDict +IceInternal::FixedReference::toProperty(const string&) const +{ + throw FixedProxyException(__FILE__, __LINE__); + + assert(false); // Cannot be reached. + return PropertyDict(); // To keep the compiler from complaining. +} + +ConnectionIPtr +IceInternal::FixedReference::getConnection(bool& compress) const +{ + switch(getMode()) + { + case Reference::ModeTwoway: + case Reference::ModeOneway: + case Reference::ModeBatchOneway: + { + if(_fixedConnection->endpoint()->datagram()) + { + throw NoEndpointException(__FILE__, __LINE__, ""); + } + break; + } + + case Reference::ModeDatagram: + case Reference::ModeBatchDatagram: + { + if(!_fixedConnection->endpoint()->datagram()) + { + throw NoEndpointException(__FILE__, __LINE__, ""); + } + break; + } + } + + // + // If a secure connection is requested or secure overrides is set, + // check if the connection is secure. + // + bool secure; + DefaultsAndOverridesPtr defaultsAndOverrides = getInstance()->defaultsAndOverrides(); + if(defaultsAndOverrides->overrideSecure) + { + secure = defaultsAndOverrides->overrideSecureValue; + } + else + { + secure = getSecure(); + } + if(secure && !_fixedConnection->endpoint()->secure()) + { + throw NoEndpointException(__FILE__, __LINE__, ""); + } + + _fixedConnection->throwException(); // Throw in case our connection is already destroyed. + + if(defaultsAndOverrides->overrideCompress) + { + compress = defaultsAndOverrides->overrideCompressValue; + } + else if(_overrideCompress) + { + compress = _compress; + } + else + { + compress = _fixedConnection->endpoint()->compress(); + } + return _fixedConnection; +} + +void +IceInternal::FixedReference::getConnection(const GetConnectionCallbackPtr& callback) const +{ + try + { + bool compress; + ConnectionIPtr connection = getConnection(compress); + callback->setConnection(connection, compress); + } + catch(const Ice::LocalException& ex) + { + callback->setException(ex); + } +} + +bool +IceInternal::FixedReference::operator==(const Reference& r) const +{ + if(this == &r) + { + return true; + } + const FixedReference* rhs = dynamic_cast<const FixedReference*>(&r); + if(!rhs || !Reference::operator==(r)) + { + return false; + } + return _fixedConnection == rhs->_fixedConnection; +} + +bool +IceInternal::FixedReference::operator!=(const Reference& r) const +{ + return !operator==(r); +} + +bool +IceInternal::FixedReference::operator<(const Reference& r) const +{ + if(this == &r) + { + return false; + } + if(Reference::operator<(r)) + { + return true; + } + if(!Reference::operator==(r)) + { + return false; + } + + const FixedReference* rhs = dynamic_cast<const FixedReference*>(&r); + if(!rhs) + { + assert(dynamic_cast<const RoutableReference*>(&r)); + return false; // As a rule, routable references are superior to fixed references. + } + return _fixedConnection < rhs->_fixedConnection; +} + +ReferencePtr +IceInternal::FixedReference::clone() const +{ + return new FixedReference(*this); +} + +IceInternal::FixedReference::FixedReference(const FixedReference& r) : + Reference(r), + _fixedConnection(r._fixedConnection) +{ +} + +IceUtil::Shared* IceInternal::upCast(IceInternal::RoutableReference* p) { return p; } + +IceInternal::RoutableReference::RoutableReference(const InstancePtr& instance, + const CommunicatorPtr& communicator, + const Identity& id, + const string& facet, + Mode mode, + bool secure, + const vector<EndpointIPtr>& endpoints, + const string& adapterId, + const LocatorInfoPtr& locatorInfo, + const RouterInfoPtr& routerInfo, + bool collocationOptimized, + bool cacheConnection, + bool preferSecure, + EndpointSelectionType endpointSelection, + int locatorCacheTimeout) : + Reference(instance, communicator, id, facet, mode, secure), + _endpoints(endpoints), + _adapterId(adapterId), + _locatorInfo(locatorInfo), + _routerInfo(routerInfo), + _collocationOptimized(collocationOptimized), + _cacheConnection(cacheConnection), + _preferSecure(preferSecure), + _endpointSelection(endpointSelection), + _locatorCacheTimeout(locatorCacheTimeout), + _overrideTimeout(false), + _timeout(-1) +{ + assert(_adapterId.empty() || _endpoints.empty()); +} + +vector<EndpointIPtr> +IceInternal::RoutableReference::getEndpoints() const +{ + return _endpoints; +} + +string +IceInternal::RoutableReference::getAdapterId() const +{ + return _adapterId; +} + +LocatorInfoPtr +IceInternal::RoutableReference::getLocatorInfo() const +{ + return _locatorInfo; +} + +RouterInfoPtr +IceInternal::RoutableReference::getRouterInfo() const +{ + return _routerInfo; +} + +bool +IceInternal::RoutableReference::getCollocationOptimized() const +{ + return _collocationOptimized; +} + +bool +IceInternal::RoutableReference::getCacheConnection() const +{ + return _cacheConnection; +} + +bool +IceInternal::RoutableReference::getPreferSecure() const +{ + return _preferSecure; +} + +Ice::EndpointSelectionType +IceInternal::RoutableReference::getEndpointSelection() const +{ + return _endpointSelection; +} + +int +IceInternal::RoutableReference::getLocatorCacheTimeout() const +{ + return _locatorCacheTimeout; +} + +string +IceInternal::RoutableReference::getConnectionId() const +{ + return _connectionId; +} + +ReferencePtr +IceInternal::RoutableReference::changeCompress(bool newCompress) const +{ + ReferencePtr r = Reference::changeCompress(newCompress); + // Also override the compress flag on the endpoints if it was updated. + if(r.get() != const_cast<RoutableReference*>(this) && !_endpoints.empty()) + { + vector<EndpointIPtr> newEndpoints; + for(vector<EndpointIPtr>::const_iterator p = _endpoints.begin(); p != _endpoints.end(); ++p) + { + newEndpoints.push_back((*p)->compress(newCompress)); + } + RoutableReferencePtr::dynamicCast(r)->_endpoints = newEndpoints; + } + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeEndpoints(const vector<EndpointIPtr>& newEndpoints) const +{ + if(newEndpoints == _endpoints) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_endpoints = newEndpoints; + r->applyOverrides(r->_endpoints); + r->_adapterId.clear(); + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeAdapterId(const string& newAdapterId) const +{ + if(newAdapterId == _adapterId) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_adapterId = newAdapterId; + r->_endpoints.clear(); + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeLocator(const LocatorPrx& newLocator) const +{ + LocatorInfoPtr newLocatorInfo = getInstance()->locatorManager()->get(newLocator); + if(newLocatorInfo == _locatorInfo) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_locatorInfo = newLocatorInfo; + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeRouter(const RouterPrx& newRouter) const +{ + RouterInfoPtr newRouterInfo = getInstance()->routerManager()->get(newRouter); + if(newRouterInfo == _routerInfo) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_routerInfo = newRouterInfo; + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeCollocationOptimized(bool newCollocationOptimized) const +{ + if(newCollocationOptimized == _collocationOptimized) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_collocationOptimized = newCollocationOptimized; + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeCacheConnection(bool newCache) const +{ + if(newCache == _cacheConnection) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_cacheConnection = newCache; + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changePreferSecure(bool newPreferSecure) const +{ + if(newPreferSecure == _preferSecure) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_preferSecure = newPreferSecure; + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeEndpointSelection(EndpointSelectionType newType) const +{ + if(newType == _endpointSelection) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_endpointSelection = newType; + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeLocatorCacheTimeout(int timeout) const +{ + if(timeout == _locatorCacheTimeout) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_locatorCacheTimeout = timeout; + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeTimeout(int newTimeout) const +{ + if(_overrideTimeout && newTimeout == _timeout) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_timeout = newTimeout; + r->_overrideTimeout = true; + if(!_endpoints.empty()) // Also override the timeout on the endpoints. + { + vector<EndpointIPtr> newEndpoints; + for(vector<EndpointIPtr>::const_iterator p = _endpoints.begin(); p != _endpoints.end(); ++p) + { + newEndpoints.push_back((*p)->timeout(newTimeout)); + } + r->_endpoints = newEndpoints; + } + return r; +} + +ReferencePtr +IceInternal::RoutableReference::changeConnectionId(const string& id) const +{ + if(id == _connectionId) + { + return RoutableReferencePtr(const_cast<RoutableReference*>(this)); + } + RoutableReferencePtr r = RoutableReferencePtr::dynamicCast(getInstance()->referenceFactory()->copy(this)); + r->_connectionId = id; + if(!_endpoints.empty()) // Also override the connection id on the endpoints. + { + vector<EndpointIPtr> newEndpoints; + for(vector<EndpointIPtr>::const_iterator p = _endpoints.begin(); p != _endpoints.end(); ++p) + { + newEndpoints.push_back((*p)->connectionId(id)); + } + r->_endpoints = newEndpoints; + } + return r; +} + +bool +IceInternal::RoutableReference::isIndirect() const +{ + return _endpoints.empty(); +} + +bool +IceInternal::RoutableReference::isWellKnown() const +{ + return _endpoints.empty() && _adapterId.empty(); +} + +void +IceInternal::RoutableReference::streamWrite(BasicStream* s) const +{ + Reference::streamWrite(s); + + Int sz = static_cast<Int>(_endpoints.size()); + s->writeSize(sz); + if(sz) + { + assert(_adapterId.empty()); + for(vector<EndpointIPtr>::const_iterator p = _endpoints.begin(); p != _endpoints.end(); ++p) + { + (*p)->streamWrite(s); + } + } + else + { + s->write(_adapterId); + } +} + +string +IceInternal::RoutableReference::toString() const +{ + // + // WARNING: Certain features, such as proxy validation in Glacier2, + // depend on the format of proxy strings. Changes to toString() and + // methods called to generate parts of the reference string could break + // these features. Please review for all features that depend on the + // format of proxyToString() before changing this and related code. + // + string result = Reference::toString(); + + if(!_endpoints.empty()) + { + vector<EndpointIPtr>::const_iterator p; + for(p = _endpoints.begin(); p != _endpoints.end(); ++p) + { + string endp = (*p)->toString(); + if(!endp.empty()) + { + result.append(":"); + result.append(endp); + } + } + } + else if(!_adapterId.empty()) + { + result.append(" @ "); + + // + // If the encoded adapter id string contains characters which the + // reference parser uses as separators, then we enclose the + // adapter id string in quotes. + // + string a = Ice::nativeToUTF8(getInstance()->initializationData().stringConverter, _adapterId); + a = IceUtilInternal::escapeString(a, ""); + if(a.find_first_of(" :@") != string::npos) + { + result.append("\""); + result.append(a); + result.append("\""); + } + else + { + result.append(a); + } + } + else + { + return result; + } + return result; +} + +PropertyDict +IceInternal::RoutableReference::toProperty(const string& prefix) const +{ + Ice::PropertyDict properties; + + properties[prefix] = toString(); + properties[prefix + ".CollocationOptimized"] = _collocationOptimized ? "1" : "0"; + properties[prefix + ".ConnectionCached"] = _cacheConnection ? "1" : "0"; + properties[prefix + ".PreferSecure"] = _preferSecure ? "1" : "0"; + properties[prefix + ".EndpointSelection"] = _endpointSelection == Random ? "Random" : "Ordered"; + + ostringstream s; + s << _locatorCacheTimeout; + properties[prefix + ".LocatorCacheTimeout"] = s.str(); + + if(_routerInfo) + { + PropertyDict routerProperties = _routerInfo->getRouter()->__reference()->toProperty(prefix + ".Router"); + for(PropertyDict::const_iterator p = routerProperties.begin(); p != routerProperties.end(); ++p) + { + properties[p->first] = p->second; + } + } + + if(_locatorInfo) + { + PropertyDict locatorProperties = _locatorInfo->getLocator()->__reference()->toProperty(prefix + ".Locator"); + for(PropertyDict::const_iterator p = locatorProperties.begin(); p != locatorProperties.end(); ++p) + { + properties[p->first] = p->second; + } + } + + return properties; +} + +int +IceInternal::RoutableReference::hashInit() const +{ + int value = Reference::hashInit(); + hashAdd(value, _adapterId); + return value; +} + +bool +IceInternal::RoutableReference::operator==(const Reference& r) const +{ + // + // Note: if(this == &r) test is performed by each non-abstract derived class. + // + if(this == &r) + { + return true; + } + + const RoutableReference* rhs = dynamic_cast<const RoutableReference*>(&r); + if(!rhs || !Reference::operator==(r)) + { + return false; + } + if(_preferSecure != rhs->_preferSecure) + { + return false; + } + if(_collocationOptimized != rhs->_collocationOptimized) + { + return false; + } + if(_cacheConnection != rhs->_cacheConnection) + { + return false; + } + if(_endpointSelection != rhs->_endpointSelection) + { + return false; + } + if(_connectionId != rhs->_connectionId) + { + return false; + } + if((_overrideTimeout != rhs->_overrideTimeout) || (_overrideTimeout && _timeout != rhs->_timeout)) + { + return false; + } + if(_routerInfo != rhs->_routerInfo) + { + return false; + } + if(_locatorInfo != rhs->_locatorInfo) + { + return false; + } + if(_endpoints != rhs->_endpoints) + { + return false; + } + if(_adapterId != rhs->_adapterId) + { + return false; + } + if(_locatorCacheTimeout != rhs->_locatorCacheTimeout) + { + return false; + } + return true; +} + +bool +IceInternal::RoutableReference::operator!=(const Reference& r) const +{ + return !operator==(r); +} + +bool +IceInternal::RoutableReference::operator<(const Reference& r) const +{ + if(this == &r) + { + return false; + } + + if(Reference::operator<(r)) + { + return true; + } + else if(!Reference::operator==(r)) + { + return false; + } + + const RoutableReference* rhs = dynamic_cast<const RoutableReference*>(&r); + if(!rhs) + { + assert(dynamic_cast<const FixedReference*>(&r)); + return true; // As a rule, routable references are superior to fixed references. + } + + if(!_preferSecure && rhs->_preferSecure) + { + return true; + } + else if(rhs->_preferSecure < _preferSecure) + { + return false; + } + if(!_collocationOptimized && rhs->_collocationOptimized) + { + return true; + } + else if(rhs->_collocationOptimized < _collocationOptimized) + { + return false; + } + if(!_cacheConnection && rhs->_cacheConnection) + { + return true; + } + else if(rhs->_cacheConnection < _cacheConnection) + { + return false; + } + if(_endpointSelection < rhs->_endpointSelection) + { + return true; + } + else if(rhs->_endpointSelection < _endpointSelection) + { + return false; + } + if(_connectionId < rhs->_connectionId) + { + return true; + } + else if(rhs->_connectionId < _connectionId) + { + return false; + } + if(!_overrideTimeout && rhs->_overrideTimeout) + { + return true; + } + else if(rhs->_overrideTimeout < _overrideTimeout) + { + return false; + } + else if(_overrideTimeout) + { + if(_timeout < rhs->_timeout) + { + return true; + } + else if(rhs->_timeout < _timeout) + { + return false; + } + } + if(_routerInfo < rhs->_routerInfo) + { + return true; + } + else if(rhs->_routerInfo < _routerInfo) + { + return false; + } + if(_locatorInfo < rhs->_locatorInfo) + { + return true; + } + else if(rhs->_locatorInfo < _locatorInfo) + { + return false; + } + if(_adapterId < rhs->_adapterId) + { + return true; + } + else if(rhs->_adapterId < _adapterId) + { + return false; + } + if(_endpoints < rhs->_endpoints) + { + return true; + } + else if(rhs->_endpoints < _endpoints) + { + return false; + } + if(_locatorCacheTimeout < rhs->_locatorCacheTimeout) + { + return true; + } + else if(rhs->_locatorCacheTimeout < _locatorCacheTimeout) + { + return false; + } + return false; +} + +ReferencePtr +IceInternal::RoutableReference::clone() const +{ + return new RoutableReference(*this); +} + +ConnectionIPtr +IceInternal::RoutableReference::getConnection(bool& comp) const +{ + if(_routerInfo) + { + // + // If we route, we send everything to the router's client + // proxy endpoints. + // + vector<EndpointIPtr> endpts = _routerInfo->getClientEndpoints(); + if(!endpts.empty()) + { + applyOverrides(endpts); + return createConnection(endpts, comp); + } + } + + if(!_endpoints.empty()) + { + return createConnection(_endpoints, comp); + } + + while(true) + { + bool cached = false; + vector<EndpointIPtr> endpts; + if(_locatorInfo) + { + endpts = _locatorInfo->getEndpoints(const_cast<RoutableReference*>(this), _locatorCacheTimeout, cached); + applyOverrides(endpts); + } + + if(endpts.empty()) + { + throw Ice::NoEndpointException(__FILE__, __LINE__, toString()); + } + + try + { + return createConnection(endpts, comp); + } + catch(const NoEndpointException&) + { + throw; // No need to retry if there's no endpoints. + } + catch(const LocalException& ex) + { + assert(_locatorInfo); + _locatorInfo->clearCache(const_cast<RoutableReference*>(this)); + + if(cached) + { + // COMPILERFIX: Braces needed to prevent BCB from causing TraceLevels refCount from + // being decremented twice when loop continues. + { + TraceLevelsPtr traceLevels = getInstance()->traceLevels(); + if(traceLevels->retry >= 2) + { + Trace out(getInstance()->initializationData().logger, traceLevels->retryCat); + out << "connection to cached endpoints failed\n" + << "removing endpoints from cache and trying one more time\n" << ex; + } + } + continue; + } + throw; + } + } + + assert(false); + return 0; +} + +void +IceInternal::RoutableReference::getConnection(const GetConnectionCallbackPtr& callback) const +{ + class Callback : public RouterInfo::GetClientEndpointsCallback + { + public: + + virtual void + setEndpoints(const vector<EndpointIPtr>& endpoints) + { + vector<EndpointIPtr> endpts = endpoints; + if(!endpts.empty()) + { + _reference->applyOverrides(endpts); + _reference->createConnection(endpts, _callback); + return; + } + + _reference->getConnectionNoRouterInfo(_callback); + } + + virtual void + setException(const Ice::LocalException& ex) + { + _callback->setException(ex); + } + + Callback(const RoutableReferencePtr& reference, const GetConnectionCallbackPtr& callback) : + _reference(reference), _callback(callback) + { + } + + private: + + const RoutableReferencePtr _reference; + const GetConnectionCallbackPtr _callback; + }; + + if(_routerInfo) + { + // + // If we route, we send everything to the router's client + // proxy endpoints. + // + _routerInfo->getClientEndpoints(new Callback(const_cast<RoutableReference*>(this), callback)); + return; + } + + getConnectionNoRouterInfo(callback); +} + +void +IceInternal::RoutableReference::getConnectionNoRouterInfo(const GetConnectionCallbackPtr& callback) const +{ + class Callback : public LocatorInfo::GetEndpointsCallback + { + public: + + class Callback2 : public Reference::GetConnectionCallback + { + public: + + virtual void + setConnection(const Ice::ConnectionIPtr& connection, bool compress) + { + _callback->setConnection(connection, compress); + } + + virtual void + setException(const Ice::LocalException& exc) + { + try + { + exc.ice_throw(); + } + catch(const Ice::NoEndpointException& ex) + { + _callback->setException(ex); // No need to retry if there's no endpoints. + } + catch(const Ice::LocalException& ex) + { + LocatorInfoPtr locatorInfo = _reference->getLocatorInfo(); + assert(locatorInfo); + locatorInfo->clearCache(_reference); + if(_cached) + { + TraceLevelsPtr traceLvls = _reference->getInstance()->traceLevels(); + if(traceLvls->retry >= 2) + { + Trace out(_reference->getInstance()->initializationData().logger, traceLvls->retryCat); + out << "connection to cached endpoints failed\n" + << "removing endpoints from cache and trying one more time\n" << ex; + } + _reference->getConnectionNoRouterInfo(_callback); // Retry. + return; + } + _callback->setException(ex); + } + } + + Callback2(const RoutableReferencePtr& reference, const GetConnectionCallbackPtr& cb, bool cached) : + _reference(reference), _callback(cb), _cached(cached) + { + } + + private: + + const RoutableReferencePtr _reference; + const GetConnectionCallbackPtr _callback; + const bool _cached; + }; + + + virtual void + setEndpoints(const vector<EndpointIPtr>& endpoints, bool cached) + { + if(endpoints.empty()) + { + _callback->setException(Ice::NoEndpointException(__FILE__, __LINE__, _reference->toString())); + return; + } + + vector<EndpointIPtr> endpts = endpoints; + _reference->applyOverrides(endpts); + _reference->createConnection(endpts, new Callback2(_reference, _callback, cached)); + } + + virtual void + setException(const Ice::LocalException& ex) + { + _callback->setException(ex); + } + + Callback(const RoutableReferencePtr& reference, const GetConnectionCallbackPtr& callback) : + _reference(reference), _callback(callback) + { + } + + private: + + const RoutableReferencePtr _reference; + const GetConnectionCallbackPtr _callback; + }; + + if(!_endpoints.empty()) + { + createConnection(_endpoints, callback); + return; + } + + if(_locatorInfo) + { + RoutableReference* self = const_cast<RoutableReference*>(this); + _locatorInfo->getEndpoints(self, _locatorCacheTimeout, new Callback(self, callback)); + } + else + { + callback->setException(Ice::NoEndpointException(__FILE__, __LINE__, toString())); + } +} + +ConnectionIPtr +IceInternal::RoutableReference::createConnection(const vector<EndpointIPtr>& allEndpoints, bool& comp) const +{ + vector<EndpointIPtr> endpoints = filterEndpoints(allEndpoints); + if(endpoints.empty()) + { + throw Ice::NoEndpointException(__FILE__, __LINE__, toString()); + } + + OutgoingConnectionFactoryPtr factory = getInstance()->outgoingConnectionFactory(); + Ice::ConnectionIPtr connection; + if(getCacheConnection() || endpoints.size() == 1) + { + // + // Get an existing connection or create one if there's no + // existing connection to one of the given endpoints. + // + connection = factory->create(endpoints, false, getEndpointSelection(), comp); + } + else + { + // + // Go through the list of endpoints and try to create the + // connection until it succeeds. This is different from just + // calling create() with the given endpoints since this might + // create a new connection even if there's an existing + // connection for one of the endpoints. + // + + auto_ptr<LocalException> exception; + vector<EndpointIPtr> endpoint; + endpoint.push_back(0); + + for(vector<EndpointIPtr>::const_iterator p = endpoints.begin(); p != endpoints.end(); ++p) + { + try + { + endpoint.back() = *p; + connection = factory->create(endpoint, p + 1 == endpoints.end(), getEndpointSelection(), comp); + break; + } + catch(const LocalException& ex) + { + exception.reset(dynamic_cast<LocalException*>(ex.ice_clone())); + } + } + + if(!connection) + { + assert(exception.get()); + exception->ice_throw(); + } + } + + assert(connection); + + // + // If we have a router, set the object adapter for this router + // (if any) to the new connection, so that callbacks from the + // router can be received over this new connection. + // + if(_routerInfo && _routerInfo->getAdapter()) + { + connection->setAdapter(_routerInfo->getAdapter()); + } + + return connection; +} + +void +IceInternal::RoutableReference::createConnection(const vector<EndpointIPtr>& allEndpoints, + const GetConnectionCallbackPtr& callback) const +{ + vector<EndpointIPtr> endpoints = filterEndpoints(allEndpoints); + if(endpoints.empty()) + { + callback->setException(Ice::NoEndpointException(__FILE__, __LINE__, toString())); + return; + } + + // + // Finally, create the connection. + // + OutgoingConnectionFactoryPtr factory = getInstance()->outgoingConnectionFactory(); + if(getCacheConnection() || endpoints.size() == 1) + { + class CB1 : public OutgoingConnectionFactory::CreateConnectionCallback + { + public: + + virtual void + setConnection(const Ice::ConnectionIPtr& connection, bool compress) + { + // + // If we have a router, set the object adapter for this router + // (if any) to the new connection, so that callbacks from the + // router can be received over this new connection. + // + if(_routerInfo && _routerInfo->getAdapter()) + { + connection->setAdapter(_routerInfo->getAdapter()); + } + _callback->setConnection(connection, compress); + } + + virtual void + setException(const Ice::LocalException& ex) + { + _callback->setException(ex); + } + + CB1(const RouterInfoPtr& routerInfo, const GetConnectionCallbackPtr& callback) : + _routerInfo(routerInfo), _callback(callback) + { + } + + private: + + const RouterInfoPtr _routerInfo; + const GetConnectionCallbackPtr _callback; + }; + + // + // Get an existing connection or create one if there's no + // existing connection to one of the given endpoints. + // + factory->create(endpoints, false, getEndpointSelection(), new CB1(_routerInfo, callback)); + return; + } + else + { + class CB2 : public OutgoingConnectionFactory::CreateConnectionCallback + { + public: + + virtual void + setConnection(const Ice::ConnectionIPtr& connection, bool compress) + { + // + // If we have a router, set the object adapter for this router + // (if any) to the new connection, so that callbacks from the + // router can be received over this new connection. + // + if(_reference->getRouterInfo() && _reference->getRouterInfo()->getAdapter()) + { + connection->setAdapter(_reference->getRouterInfo()->getAdapter()); + } + _callback->setConnection(connection, compress); + } + + virtual void + setException(const Ice::LocalException& ex) + { + if(!_exception.get()) + { + _exception.reset(dynamic_cast<Ice::LocalException*>(ex.ice_clone())); + } + + if(++_i == _endpoints.size()) + { + _callback->setException(*_exception.get()); + return; + } + + const bool more = _i != _endpoints.size() - 1; + vector<EndpointIPtr> endpoint; + endpoint.push_back(_endpoints[_i]); + + OutgoingConnectionFactoryPtr factory = _reference->getInstance()->outgoingConnectionFactory(); + factory->create(endpoint, more, _reference->getEndpointSelection(), this); + } + + CB2(const RoutableReferencePtr& reference, const vector<EndpointIPtr>& endpoints, + const GetConnectionCallbackPtr& callback) : + _reference(reference), + _endpoints(endpoints), + _callback(callback), + _i(0) + { + } + + private: + + const RoutableReferencePtr _reference; + const vector<EndpointIPtr> _endpoints; + const GetConnectionCallbackPtr _callback; + size_t _i; + std::auto_ptr<Ice::LocalException> _exception; + }; + + // + // Go through the list of endpoints and try to create the + // connection until it succeeds. This is different from just + // calling create() with the given endpoints since this might + // create a new connection even if there's an existing + // connection for one of the endpoints. + // + + vector<EndpointIPtr> endpt; + endpt.push_back(endpoints[0]); + RoutableReference* self = const_cast<RoutableReference*>(this); + factory->create(endpt, true, getEndpointSelection(), new CB2(self, endpoints, callback)); + return; + } +} + +void +IceInternal::RoutableReference::applyOverrides(vector<EndpointIPtr>& endpoints) const +{ + for(vector<EndpointIPtr>::iterator p = endpoints.begin(); p != endpoints.end(); ++p) + { + *p = (*p)->connectionId(_connectionId); + if(_overrideCompress) + { + *p = (*p)->compress(_compress); + } + if(_overrideTimeout) + { + *p = (*p)->timeout(_timeout); + } + } +} + +IceInternal::RoutableReference::RoutableReference(const RoutableReference& r) : + Reference(r), + _endpoints(r._endpoints), + _adapterId(r._adapterId), + _locatorInfo(r._locatorInfo), + _routerInfo(r._routerInfo), + _collocationOptimized(r._collocationOptimized), + _cacheConnection(r._cacheConnection), + _preferSecure(r._preferSecure), + _endpointSelection(r._endpointSelection), + _locatorCacheTimeout(r._locatorCacheTimeout), + _overrideTimeout(r._overrideTimeout), + _timeout(r._timeout), + _connectionId(r._connectionId) +{ +} + +namespace +{ + +struct EndpointIsOpaque : public unary_function<EndpointIPtr, bool> +{ +public: + + bool + operator()(EndpointIPtr p) const + { + return dynamic_cast<OpaqueEndpointI*>(p.get()) != 0; + } +}; + +} + +vector<EndpointIPtr> +IceInternal::RoutableReference::filterEndpoints(const vector<EndpointIPtr>& allEndpoints) const +{ + vector<EndpointIPtr> endpoints = allEndpoints; + + // + // Filter out unknown endpoints. + // + endpoints.erase(remove_if(endpoints.begin(), endpoints.end(), EndpointIsOpaque()), endpoints.end()); + + // + // Filter out endpoints according to the mode of the reference. + // + switch(getMode()) + { + case Reference::ModeTwoway: + case Reference::ModeOneway: + case Reference::ModeBatchOneway: + { + // + // Filter out datagram endpoints. + // + endpoints.erase(remove_if(endpoints.begin(), endpoints.end(), Ice::constMemFun(&EndpointI::datagram)), + endpoints.end()); + break; + } + + case Reference::ModeDatagram: + case Reference::ModeBatchDatagram: + { + // + // Filter out non-datagram endpoints. + // + endpoints.erase(remove_if(endpoints.begin(), endpoints.end(), + not1(Ice::constMemFun(&EndpointI::datagram))), + endpoints.end()); + break; + } + } + + // + // Sort the endpoints according to the endpoint selection type. + // + switch(getEndpointSelection()) + { + case Random: + { + RandomNumberGenerator rng; + random_shuffle(endpoints.begin(), endpoints.end(), rng); + break; + } + case Ordered: + { + // Nothing to do. + break; + } + default: + { + assert(false); + break; + } + } + + // + // If a secure connection is requested or secure overrides is set, + // remove all non-secure endpoints. Otherwise if preferSecure is set + // make secure endpoints prefered. By default make non-secure + // endpoints preferred over secure endpoints. + // + DefaultsAndOverridesPtr overrides = getInstance()->defaultsAndOverrides(); + if(overrides->overrideSecure ? overrides->overrideSecureValue : getSecure()) + { + endpoints.erase(remove_if(endpoints.begin(), endpoints.end(), not1(Ice::constMemFun(&EndpointI::secure))), + endpoints.end()); + } + else if(getPreferSecure()) + { + // + // We must use stable_partition() instead of just simply + // partition(), because otherwise some STL implementations + // order our now randomized endpoints. + // + stable_partition(endpoints.begin(), endpoints.end(), Ice::constMemFun(&EndpointI::secure)); + } + else + { + // + // We must use stable_partition() instead of just simply + // partition(), because otherwise some STL implementations + // order our now randomized endpoints. + // + stable_partition(endpoints.begin(), endpoints.end(), not1(Ice::constMemFun(&EndpointI::secure))); + } + + return endpoints; +} |