diff options
Diffstat (limited to 'cpp/src/Ice/BasicStream.cpp')
-rw-r--r-- | cpp/src/Ice/BasicStream.cpp | 460 |
1 files changed, 387 insertions, 73 deletions
diff --git a/cpp/src/Ice/BasicStream.cpp b/cpp/src/Ice/BasicStream.cpp index 324b2795cc1..62f559a8b18 100644 --- a/cpp/src/Ice/BasicStream.cpp +++ b/cpp/src/Ice/BasicStream.cpp @@ -19,10 +19,9 @@ #include <Ice/ProxyFactory.h> #include <Ice/ObjectFactory.h> #include <Ice/ObjectFactoryManager.h> -#include <Ice/UserExceptionFactory.h> -#include <Ice/UserExceptionFactoryManager.h> #include <Ice/LocalException.h> #include <Ice/Protocol.h> +#include <Ice/FactoryTable.h> template<typename InputIter, typename OutputIter> void @@ -46,8 +45,6 @@ using namespace std; using namespace Ice; using namespace IceInternal; -const string IceInternal::BasicStream::_emptyString; -const string IceInternal::BasicStream::_iceObjectId("::Ice::Object"); const string IceInternal::BasicStream::_userExceptionId("::Ice::UserException"); IceInternal::BasicStream::BasicStream(Instance* instance) : @@ -110,6 +107,40 @@ IceInternal::BasicStream::reserve(int total) b.reserve(total); } +IceInternal::BasicStream::WriteEncaps::WriteEncaps() + : writeIndex(0), toBeMarshaledMap(0), marshaledMap(0), typeIdIndex(0), typeIdMap(0) +{ +} + +IceInternal::BasicStream::WriteEncaps::WriteEncaps(const WriteEncaps& rhs) +{ + start = rhs.start; + writeIndex = rhs.writeIndex; + typeIdIndex = rhs.typeIdIndex; + if(rhs.toBeMarshaledMap) + { + toBeMarshaledMap = new PtrToIndexMap(*rhs.toBeMarshaledMap); + marshaledMap = new PtrToIndexMap(*rhs.marshaledMap); + typeIdMap = new TypeIdWriteMap(*rhs.typeIdMap); + } + else + { + toBeMarshaledMap = 0; + marshaledMap = 0; + typeIdMap = 0; + } +} + +IceInternal::BasicStream::WriteEncaps::~WriteEncaps() +{ + if(toBeMarshaledMap) + { + delete toBeMarshaledMap; + delete marshaledMap; + delete typeIdMap; + } +} + void IceInternal::BasicStream::startWriteEncaps() { @@ -144,6 +175,41 @@ IceInternal::BasicStream::endWriteEncaps() #endif } +IceInternal::BasicStream::ReadEncaps::ReadEncaps() + : patchMap(0), unmarshaledMap(0), typeIdIndex(0), typeIdMap(0) +{ +} + +IceInternal::BasicStream::ReadEncaps::ReadEncaps(const ReadEncaps& rhs) +{ + start = rhs.start; + encodingMajor = rhs.encodingMajor; + encodingMinor = rhs.encodingMinor; + typeIdIndex = rhs.typeIdIndex; + if(rhs.patchMap) + { + patchMap = new PatchMap(*rhs.patchMap); + unmarshaledMap = new IndexToPtrMap(*rhs.unmarshaledMap); + typeIdMap = new TypeIdReadMap(*rhs.typeIdMap); + } + else + { + patchMap = 0; + unmarshaledMap = 0; + typeIdMap = 0; + } +} + +IceInternal::BasicStream::ReadEncaps::~ReadEncaps() +{ + if(patchMap) + { + delete patchMap; + delete unmarshaledMap; + delete typeIdMap; + } +} + void IceInternal::BasicStream::startReadEncaps() { @@ -280,6 +346,58 @@ IceInternal::BasicStream::skipEncaps() } void +IceInternal::BasicStream::startWriteSlice() +{ + write(Int(0)); // Placeholder for the slice length + _writeSlice = b.size(); +} + +void +IceInternal::BasicStream::endWriteSlice() +{ + Int sz = b.size() - _writeSlice + sizeof(Int); + const Byte* p = reinterpret_cast<const Byte*>(&sz); +#ifdef ICE_UTIL_BIGENDIAN + reverse_copy(p, p + sizeof(Int), b.begin() + _writeSlice - sizeof(Int)); +#else + copy(p, p + sizeof(Int), b.begin() + _writeSlice - sizeof(Int)); +#endif +} + +void +IceInternal::BasicStream::startReadSlice() +{ + Int sz; + read(sz); + if(sz < 0) + { + throw NegativeSizeException(__FILE__, __LINE__); + } + _readSlice = i - b.begin(); +} + +void +IceInternal::BasicStream::endReadSlice() +{ +} + +void +IceInternal::BasicStream::skipSlice() +{ + Int sz; + read(sz); + if(sz < 0) + { + throw NegativeSizeException(__FILE__, __LINE__); + } + i += sz - sizeof(Int); + if(i > b.end()) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } +} + +void IceInternal::BasicStream::writeSize(Int v) { if(v > 127) @@ -313,6 +431,46 @@ IceInternal::BasicStream::readSize(Ice::Int& v) } void +BasicStream::writeTypeId(const string& id) +{ + TypeIdWriteMap::const_iterator i = _currentWriteEncaps->typeIdMap->find(id); + if(i != _currentWriteEncaps->typeIdMap->end()) + { + write(true); + writeSize(i->second); + } + else + { + _currentWriteEncaps->typeIdMap->insert(make_pair(id, ++_currentWriteEncaps->typeIdIndex)); + write(false); + write(id); + } +} + +void +BasicStream::readTypeId(string& id) +{ + bool isIndex; + read(isIndex); + if(isIndex) + { + Ice::Int index; + readSize(index); + TypeIdReadMap::const_iterator i = _currentReadEncaps->typeIdMap->find(index); + if(i == _currentReadEncaps->typeIdMap->end()) + { + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); + } + id = i->second; + } + else + { + read(id); + _currentReadEncaps->typeIdMap->insert(make_pair(++_currentReadEncaps->typeIdIndex, id)); + } +} + +void IceInternal::BasicStream::writeBlob(const vector<Byte>& v) { size_t pos = b.size(); @@ -893,66 +1051,111 @@ IceInternal::BasicStream::read(ObjectPrx& v) void IceInternal::BasicStream::write(const ObjectPtr& v) { - if(!_currentWriteEncaps) // Lazy initialization + if(!_currentWriteEncaps) // Lazy initialization { _writeEncapsStack.resize(1); _currentWriteEncaps = &_writeEncapsStack.back(); + _currentWriteEncaps->start = b.size(); + _currentWriteEncaps->toBeMarshaledMap = 0; } - map<ObjectPtr, Int>::const_iterator p = _currentWriteEncaps->objectsWritten.find(v.get()); - if(p != _currentWriteEncaps->objectsWritten.end()) + if(!_currentWriteEncaps->toBeMarshaledMap) // Lazy initialization { - write(p->second); + _currentWriteEncaps->toBeMarshaledMap = new PtrToIndexMap; + _currentWriteEncaps->marshaledMap = new PtrToIndexMap; + _currentWriteEncaps->typeIdMap = new TypeIdWriteMap; } - else + + if(v) { - write(Int(-1)); - - if(v) + // + // Look for this instance in the to-be-marshaled map. + // + PtrToIndexMap::iterator p = _currentWriteEncaps->toBeMarshaledMap->find(v); + if(p == _currentWriteEncaps->toBeMarshaledMap->end()) { - Int num = static_cast<Int>(_currentWriteEncaps->objectsWritten.size()); - _currentWriteEncaps->objectsWritten[v.get()] = num; - write(v->ice_id()); - v->__write(this); - } - else - { - write(_emptyString); + // + // Didn't find it, try the marshaled map next. + // + PtrToIndexMap::iterator q = _currentWriteEncaps->marshaledMap->find(v); + if(q == _currentWriteEncaps->marshaledMap->end()) + { + // + // We haven't seen this instance previously, create a new index, and + // insert it into the to-be-marshaled map. + // + q = _currentWriteEncaps->toBeMarshaledMap->insert( + _currentWriteEncaps->toBeMarshaledMap->end(), + make_pair(v, ++_currentWriteEncaps->writeIndex)); + } + p = q; } + // + // Write the index for the instance. + // + write(-(p->second)); + } + else + { + write(0); // Write null pointer } } void -IceInternal::BasicStream::read(const string& signatureType, const ObjectFactoryPtr& factory, ObjectPtr& v) +IceInternal::BasicStream::read(PatchFunc patchFunc, void* patchAddr) { - if(!_currentReadEncaps) // Lazy initialization + if(!_currentReadEncaps) // Lazy initialization { _readEncapsStack.resize(1); _currentReadEncaps = &_readEncapsStack.back(); } - Int pos; - read(pos); - - if(pos >= 0) + if(!_currentReadEncaps->patchMap) // Lazy initialization { - if(static_cast<vector<ObjectPtr>::size_type>(pos) >= _currentReadEncaps->objectsRead.size()) - { - throw IllegalIndirectionException(__FILE__, __LINE__); - } - v = _currentReadEncaps->objectsRead[pos]; + _currentReadEncaps->patchMap = new PatchMap; + _currentReadEncaps->unmarshaledMap = new IndexToPtrMap; + _currentReadEncaps->typeIdMap = new TypeIdReadMap; } - else + + ObjectPtr v; + + Int index; + read(index); + + if(index == 0) { - string id; - read(id); + patchFunc(patchAddr, v); // Null Ptr + return; + } - if(id.empty()) + if(index < 0 && patchAddr) + { + PatchMap::iterator p = _currentReadEncaps->patchMap->find(-index); + if(p == _currentReadEncaps->patchMap->end()) { - v = 0; - return; + // + // We have no outstanding instances to be patched for this index, so make a new entry + // in the patch map. + // + p = _currentReadEncaps->patchMap->insert(make_pair(-index, PatchList())).first; } - else if(id == _iceObjectId) + // + // Append a patch entry for this instance. + // + PatchEntry e; + e.patchFunc = patchFunc; + e.patchAddr = patchAddr; + p->second.push_back(e); + patchPointers(-index, p, _currentReadEncaps->unmarshaledMap->end()); + return; + } + assert(index > 0); + + while(1) + { + string id; + readTypeId(id); + if(id == Ice::Object::ice_staticId()) { v = new ::Ice::Object; } @@ -963,68 +1166,179 @@ IceInternal::BasicStream::read(const string& signatureType, const ObjectFactoryP { v = userFactory->create(id); } - - if(!v && id == signatureType) + if(!v) { - assert(factory); - v = factory->create(id); - assert(v); + ObjectFactoryPtr of = Ice::factoryTable->getObjectFactory(id); + if(of) + { + v = of->create(id); + assert(v); + } } - if(!v) { - NoObjectFactoryException ex(__FILE__, __LINE__); - ex.type = id; - throw ex; + skipSlice(); // Slice off this derived part -- we don't understand it. + continue; } } - _currentReadEncaps->objectsRead.push_back(v.get()); - v->__read(this); + + IndexToPtrMap::const_iterator unmarshaledPos = + _currentReadEncaps->unmarshaledMap->insert(make_pair(index, v)).first; + + v->__read(this, false); + patchPointers(index, _currentReadEncaps->patchMap->end(), unmarshaledPos); + return; } + + // + // We can't possibly end up here: at the very least, the type ID "::Ice::Object" must be recognized, or + // client and server were compiled with mismatched Slice definitions. + // + throw UnmarshalOutOfBoundsException(__FILE__, __LINE__); } void IceInternal::BasicStream::write(const UserException& v) { - write(v.__getExceptionIds()[0]); + write(v.__usesClasses()); v.__write(this); + if(v.__usesClasses()) + { + writePendingObjects(); + } } -Int -IceInternal::BasicStream::throwException(const string* throwsBegin, const string* throwsEnd) +void +IceInternal::BasicStream::throwException() { + bool usesClasses; + read(usesClasses); + string id; read(id); - UserExceptionFactoryPtr factory = _instance->userExceptionFactoryManager()->find(id); - - if(factory) + while(!id.empty()) { - try - { - factory->createAndThrow(id); - } - catch(UserException& ex) + // + // Look for a factory for this ID. + // + UserExceptionFactoryPtr factory = factoryTable->getExceptionFactory(id); + if(factory) { - for(const string* p = ex.__getExceptionIds(); *p != _userExceptionId != 0; ++p) + // + // Got factory -- get the factory to instantiate the exception, initialize the + // exception members, and throw the exception. + // + try + { + factory->createAndThrow(); + } + catch(UserException& ex) { - if(binary_search(throwsBegin, throwsEnd, string(*p))) + ex.__read(this, false); + if(usesClasses) { - ex.__read(this); - ex.ice_throw(); + readPendingObjects(); } + ex.ice_throw(); } - - throw UnknownUserException(__FILE__, __LINE__); + } + else + { + skipSlice(); // Slice off what we don't understand + read(id); // Read type id for next encapsulation + } + } + // + // Getting here should be impossible: we can get here only if the sender has marshaled a sequence + // of type IDs, none of which we have factory for. this means that sender and receiver disagree + // about the Slice definitions they use. + // + throw UnknownUserException(__FILE__, __LINE__); +} + +void +BasicStream::writePendingObjects() +{ + while(_currentWriteEncaps->toBeMarshaledMap->size()) + { + PtrToIndexMap savedMap = *_currentWriteEncaps->toBeMarshaledMap; + writeSize(static_cast<Int>(savedMap.size())); + for(PtrToIndexMap::iterator p = savedMap.begin(); p != savedMap.end(); ++p) + { + // + // Add an instance from the old to-be-marshaled map to the marshaled map and then + // ask the instance to marshal itself. Any new class instances that are triggered + // by the classes marshaled are added to toBeMarshaledMap. + // + _currentWriteEncaps->marshaledMap->insert(*p); + writeInstance(p->first, p->second); + } + + // + // We have marshaled all the instances for this pass, substract what we have + // marshaled from the toBeMarshaledMap. + // + PtrToIndexMap newMap; + set_difference(_currentWriteEncaps->toBeMarshaledMap->begin(), _currentWriteEncaps->toBeMarshaledMap->end(), + savedMap.begin(), savedMap.end(), + insert_iterator<PtrToIndexMap>(newMap, newMap.begin())); + *_currentWriteEncaps->toBeMarshaledMap = newMap; + } + writeSize(0); // Zero marker indicates end of sequence of sequences of instances. +} + +void +BasicStream::readPendingObjects() +{ + Int num; + do + { + readSize(num); + for(int i = num; i > 0; --i) + { + read(0, 0); + } + } + while(num); +} + +void +BasicStream::writeInstance(const ObjectPtr& v, Int index) +{ + write(index); + v->__write(this); +} + +void +BasicStream::patchPointers(Int index, PatchMap::iterator patchPos, IndexToPtrMap::const_iterator unmarshaledPos) +{ + // + // Called whenever we have unmarshaled a new instance. The index is the index of the instance just unmarshaled + // and patchPos is an iterator into the patch map at that index. (Either may be null, in which case we + // search the patch map and/or the unmarshaled map.) + // Patch any pointers in the patch map with the new address. + // + if(patchPos == _currentReadEncaps->patchMap->end()) + { + patchPos = _currentReadEncaps->patchMap->find(index); + } + + if(unmarshaledPos == _currentReadEncaps->unmarshaledMap->end()) + { + unmarshaledPos = _currentReadEncaps->unmarshaledMap->find(index); + if(unmarshaledPos == _currentReadEncaps->unmarshaledMap->end()) + { + return; // Nothing to do } } - pair<const string*, const string*> p = equal_range(throwsBegin, throwsEnd, id); - if(p.first != p.second) + if(patchPos != _currentReadEncaps->patchMap->end()) { - return static_cast<Int>(p.first - throwsBegin); + ObjectPtr v = unmarshaledPos->second; + for(PatchList::iterator i = patchPos->second.begin(); i != patchPos->second.end(); ++i) + { + (*i->patchFunc)(i->patchAddr, v); + } + _currentReadEncaps->patchMap->erase(patchPos); } - - NoUserExceptionFactoryException ex(__FILE__, __LINE__); - ex.type = id; - throw ex; } |