diff options
Diffstat (limited to 'binaryurp/source/reader.cxx')
-rwxr-xr-x | binaryurp/source/reader.cxx | 553 |
1 files changed, 553 insertions, 0 deletions
diff --git a/binaryurp/source/reader.cxx b/binaryurp/source/reader.cxx new file mode 100755 index 000000000000..f622fb5b0c42 --- /dev/null +++ b/binaryurp/source/reader.cxx @@ -0,0 +1,553 @@ +/************************************************************************* +* +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +* +* Copyright 2000, 2011 Oracle and/or its affiliates. +* +* OpenOffice.org - a multi-platform office productivity suite +* +* This file is part of OpenOffice.org. +* +* OpenOffice.org is free software: you can redistribute it and/or modify +* it under the terms of the GNU Lesser General Public License version 3 +* only, as published by the Free Software Foundation. +* +* OpenOffice.org is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License version 3 for more details +* (a copy is included in the LICENSE file that accompanied this code). +* +* You should have received a copy of the GNU Lesser General Public License +* version 3 along with OpenOffice.org. If not, see +* <http://www.openoffice.org/license.html> +* for a copy of the LGPLv3 License. +* +************************************************************************/ + +#include "sal/config.h" + +#include <exception> +#include <memory> +#include <vector> + +#include "com/sun/star/connection/XConnection.hpp" +#include "com/sun/star/io/IOException.hpp" +#include "com/sun/star/uno/Any.hxx" +#include "com/sun/star/uno/Exception.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/RuntimeException.hpp" +#include "com/sun/star/uno/Sequence.hxx" +#include "com/sun/star/uno/Type.hxx" +#include "com/sun/star/uno/XCurrentContext.hpp" +#include "com/sun/star/uno/XInterface.hpp" +#include "cppu/unotype.hxx" +#include "osl/diagnose.h" +#include "rtl/byteseq.h" +#include "rtl/string.h" +#include "rtl/textenc.h" +#include "rtl/ustring.h" +#include "rtl/ustring.hxx" +#include "sal/types.h" +#include "typelib/typeclass.h" +#include "typelib/typedescription.h" +#include "typelib/typedescription.hxx" +#include "uno/lbnames.h" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "incomingreply.hxx" +#include "incomingrequest.hxx" +#include "outgoingrequest.hxx" +#include "reader.hxx" +#include "specialfunctionids.hxx" +#include "unmarshal.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +css::uno::Sequence< sal_Int8 > read( + css::uno::Reference< css::connection::XConnection > const & connection, + sal_uInt32 size, bool eofOk) +{ + OSL_ASSERT(connection.is()); + if (size > SAL_MAX_INT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Reader: block size too large")), + css::uno::Reference< css::uno::XInterface >()); + } + css::uno::Sequence< sal_Int8 > buf; + sal_Int32 n = connection->read(buf, static_cast< sal_Int32 >(size)); + if (n == 0 && eofOk) { + return css::uno::Sequence< sal_Int8 >(); + } + if (n != static_cast< sal_Int32 >(size)) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Reader: premature end of input")), + css::uno::Reference< css::uno::XInterface >()); + } + OSL_ASSERT(buf.getLength() == static_cast< sal_Int32 >(size)); + return buf; +} + +extern "C" void SAL_CALL request(void * pThreadSpecificData) { + OSL_ASSERT(pThreadSpecificData != 0); + std::auto_ptr< IncomingRequest >( + static_cast< IncomingRequest * >(pThreadSpecificData))-> + execute(); +} + +} + +Reader::Reader(rtl::Reference< Bridge > const & bridge): bridge_(bridge) { + OSL_ASSERT(bridge.is()); + acquire(); +} + +Reader::~Reader() {} + +void Reader::run() { + setName("binaryurpReader"); + try { + bridge_->sendRequestChangeRequest(); + css::uno::Reference< css::connection::XConnection > con( + bridge_->getConnection()); + for (;;) { + css::uno::Sequence< sal_Int8 > s(read(con, 8, true)); + if (s.getLength() == 0) { + break; + } + Unmarshal header(bridge_, state_, s); + sal_uInt32 size = header.read32(); + sal_uInt32 count = header.read32(); + header.done(); + if (count == 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Reader: block with zero message count" + " received")), + css::uno::Reference< css::uno::XInterface >()); + } + Unmarshal block(bridge_, state_, read(con, size, false)); + for (sal_uInt32 i = 0; i != count; ++i) { + readMessage(block); + } + block.done(); + } + } catch (css::uno::Exception & e) { + OSL_TRACE( + OSL_LOG_PREFIX "caught UNO exception '%s'", + rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); + } catch (std::exception & e) { + OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what()); + } + bridge_->terminate(); +} + +void Reader::onTerminated() { + release(); +} + +void Reader::readMessage(Unmarshal & unmarshal) { + sal_uInt8 flags1 = unmarshal.read8(); + bool newType; + bool newOid; + bool newTid; + bool forceSynchronous; + sal_uInt16 functionId; + if ((flags1 & 0x80) != 0) { // bit 7: LONGHEADER + if ((flags1 & 0x40) == 0) { // bit 6: REQUEST + readReplyMessage(unmarshal, flags1); + return; + } + newType = (flags1 & 0x20) != 0; // bit 5: NEWTYPE + newOid = (flags1 & 0x10) != 0; // bit 4: NEWOID + newTid = (flags1 & 0x08) != 0; // bit 3: NEWTID + if ((flags1 & 0x01) != 0) { // bit 0: MOREFLAGSS + sal_uInt8 flags2 = unmarshal.read8(); + forceSynchronous = (flags2 & 0x80) != 0; // bit 7: MUSTREPLY + if (((flags2 & 0x40) != 0) != forceSynchronous) { + // bit 6: SYNCHRONOUS + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with MUSTREPLY != SYNCHRONOUS" + " received")), + css::uno::Reference< css::uno::XInterface >()); + } + } else { + forceSynchronous = false; + } + functionId = ((flags1 & 0x04) != 0) // bit 2: FUNCTIONID16 + ? unmarshal.read16() : unmarshal.read8(); + } else { + newType = false; + newOid = false; + newTid = false; + forceSynchronous = false; + functionId = ((flags1 & 0x40) != 0) // bit 6: FUNCTIONID14 + ? ((flags1 & 0x3F) << 8) | unmarshal.read8() : flags1 & 0x3F; + } + css::uno::TypeDescription type; + if (newType) { + type = unmarshal.readType(); + lastType_ = type; + } else { + if (!lastType_.is()) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with NEWTYPE received when last" + " interface type has not yet been set")), + css::uno::Reference< css::uno::XInterface >()); + } + type = lastType_; + } + rtl::OUString oid; + if (newOid) { + oid = unmarshal.readOid(); + if (oid.getLength() == 0) { + throw css::io::IOException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "binaryurp::Unmarshal: emtpy OID")), + css::uno::Reference< css::uno::XInterface >()); + } + lastOid_ = oid; + } else { + if (lastOid_.getLength() == 0) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with NEWOID received when last" + " OID has not yet been set")), + css::uno::Reference< css::uno::XInterface >()); + } + oid = lastOid_; + } + rtl::ByteSequence tid(getTid(unmarshal, newTid)); + lastTid_ = tid; + type.makeComplete(); + if (type.get()->eTypeClass != typelib_TypeClass_INTERFACE) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with non-interface interface type" + " received")), + css::uno::Reference< css::uno::XInterface >()); + } + typelib_InterfaceTypeDescription * itd = + reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()); + if (functionId >= itd->nMapFunctionIndexToMemberIndex) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with unknown function ID received")), + css::uno::Reference< css::uno::XInterface >()); + } + sal_Int32 memberId = itd->pMapFunctionIndexToMemberIndex[functionId]; + css::uno::TypeDescription memberTd(itd->ppAllMembers[memberId]); + memberTd.makeComplete(); + OSL_ASSERT(memberTd.is()); + bool protProps = bridge_->isProtocolPropertiesRequest(oid, type); + bool ccMode = !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE && + bridge_->isCurrentContextMode(); + css::uno::UnoInterfaceReference cc; + if (ccMode) { + css::uno::TypeDescription t( + cppu::UnoType< css::uno::Reference< css::uno::XCurrentContext > >:: + get()); + cc.set( + *static_cast< uno_Interface ** >( + unmarshal.readValue(t).getValue(t))); + } + bool synchronous; + if (memberTd.get()->eTypeClass == typelib_TypeClass_INTERFACE_METHOD && + (reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( + memberTd.get())-> + bOneWay)) + { + synchronous = forceSynchronous; + } else { + if (forceSynchronous) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: synchronous request message with non-oneway" + " function ID received")), + css::uno::Reference< css::uno::XInterface >()); + } + synchronous = true; + } + bool setter = false; + std::vector< BinaryAny > inArgs; + switch (memberTd.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + setter = itd->pMapMemberIndexToFunctionIndex[memberId] != functionId; + // pMapMemberIndexToFunctionIndex contains function index of + // attribute getter + if (setter) { + inArgs.push_back( + unmarshal.readValue( + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + memberTd.get())-> + pAttributeTypeRef))); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( + memberTd.get()); + for (sal_Int32 i = 0; i != mtd->nParams; ++i) { + if (mtd->pParams[i].bIn) { + inArgs.push_back( + unmarshal.readValue( + css::uno::TypeDescription( + mtd->pParams[i].pTypeRef))); + } + } + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + bridge_->incrementCalls( + !protProps && functionId != SPECIAL_FUNCTION_ID_RELEASE); + if (protProps) { + switch (functionId) { + case SPECIAL_FUNCTION_ID_REQUEST_CHANGE: + bridge_->handleRequestChangeRequest(tid, inArgs); + break; + case SPECIAL_FUNCTION_ID_COMMIT_CHANGE: + bridge_->handleCommitChangeRequest(tid, inArgs); + break; + default: + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with UrpProtocolProperties OID" + " and unknown function ID received")), + css::uno::Reference< css::uno::XInterface >()); + } + } else { + css::uno::UnoInterfaceReference obj; + switch (functionId) { + case SPECIAL_FUNCTION_ID_QUERY_INTERFACE: + obj = bridge_->findStub(oid, type); + if (!obj.is()) { + OSL_ASSERT( + inArgs.size() == 1 + && inArgs[0].getType().equals( + css::uno::TypeDescription( + cppu::UnoType< css::uno::Type >::get()))); + if (!(type.equals( + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< + css::uno::XInterface > >::get())) + && (css::uno::TypeDescription( + *static_cast< + typelib_TypeDescriptionReference ** >( + inArgs[0].getValue(inArgs[0].getType()))). + equals( + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< + css::uno::XInterface > >::get()))))) + { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: queryInterface request message with" + " unknown OID received")), + css::uno::Reference< css::uno::XInterface >()); + } + } + break; + case SPECIAL_FUNCTION_ID_RESERVED: + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with unknown function ID 1" + " received")), + css::uno::Reference< css::uno::XInterface >()); + case SPECIAL_FUNCTION_ID_RELEASE: + break; + default: + obj = bridge_->findStub(oid, type); + if (!obj.is()) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: request message with unknown OID received")), + css::uno::Reference< css::uno::XInterface >()); + } + break; + } + std::auto_ptr< IncomingRequest > req( + new IncomingRequest( + bridge_, tid, oid, obj, type, functionId, synchronous, memberTd, + setter, inArgs, ccMode, cc)); + if (synchronous) { + bridge_->incrementActiveCalls(); + } + uno_threadpool_putJob( + bridge_->getThreadPool(), tid.getHandle(), req.get(), &request, + !synchronous); + req.release(); + } +} + +void Reader::readReplyMessage(Unmarshal & unmarshal, sal_uInt8 flags1) { + rtl::ByteSequence tid(getTid(unmarshal, (flags1 & 0x08) != 0)); + // bit 3: NEWTID + lastTid_ = tid; + OutgoingRequest req(bridge_->lastOutgoingRequest(tid)); + bool exc = (flags1 & 0x20) != 0; // bit 5: EXCEPTION + BinaryAny ret; + std::vector< BinaryAny > outArgs; + if (exc) { + ret = unmarshal.readValue( + css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get())); + if (!typelib_typedescription_isAssignableFrom( + (css::uno::TypeDescription( + cppu::UnoType< css::uno::RuntimeException >::get()). + get()), + ret.getType().get())) + { + sal_Int32 n = 0; + typelib_TypeDescriptionReference ** p = 0; + switch (req.member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_InterfaceAttributeTypeDescription * atd = + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + req.member.get()); + n = req.setter ? atd->nSetExceptions : atd->nGetExceptions; + p = req.setter + ? atd->ppSetExceptions : atd->ppGetExceptions; + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + req.member.get()); + n = mtd->nExceptions; + p = mtd->ppExceptions; + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + bool ok = false; + for (sal_Int32 i = 0; i != n; ++i) { + if (typelib_typedescriptionreference_isAssignableFrom( + p[i], + reinterpret_cast< typelib_TypeDescriptionReference * >( + ret.getType().get()))) + { + ok = true; + break; + } + } + if (!ok) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: reply message with bad exception type" + " received")), + css::uno::Reference< css::uno::XInterface >()); + } + } + } else { + switch (req.member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (!req.setter) { + ret = unmarshal.readValue( + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + req.member.get())-> + pAttributeTypeRef)); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + req.member.get()); + ret = unmarshal.readValue( + css::uno::TypeDescription(mtd->pReturnTypeRef)); + for (sal_Int32 i = 0; i != mtd->nParams; ++i) { + if (mtd->pParams[i].bOut) { + outArgs.push_back( + unmarshal.readValue( + css::uno::TypeDescription( + mtd->pParams[i].pTypeRef))); + } + } + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + } + switch (req.kind) { + case OutgoingRequest::KIND_NORMAL: + { + std::auto_ptr< IncomingReply > resp( + new IncomingReply(exc, ret, outArgs)); + uno_threadpool_putJob( + bridge_->getThreadPool(), tid.getHandle(), resp.get(), 0, + false); + resp.release(); + break; + } + case OutgoingRequest::KIND_REQUEST_CHANGE: + OSL_ASSERT(outArgs.empty()); + bridge_->handleRequestChangeReply(exc, ret); + break; + case OutgoingRequest::KIND_COMMIT_CHANGE: + OSL_ASSERT(outArgs.empty()); + bridge_->handleCommitChangeReply(exc, ret); + break; + default: + OSL_ASSERT(false); // this cannot happen + break; + } +} + +rtl::ByteSequence Reader::getTid(Unmarshal & unmarshal, bool newTid) const { + if (newTid) { + return unmarshal.readTid(); + } + if (lastTid_.getLength() == 0) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "URP: message with NEWTID received when last TID has not" + " yet been set")), + css::uno::Reference< css::uno::XInterface >()); + } + return lastTid_; +} + +} |