diff options
author | sb <sb@openoffice.org> | 2011-01-26 09:26:59 +0100 |
---|---|---|
committer | sb <sb@openoffice.org> | 2011-01-26 09:26:59 +0100 |
commit | 138ab06ecc2c288963dac707ebc94b69ce92f39d (patch) | |
tree | 222c69a4c6dfa53801c2b128fcd4e19187cb5a93 /binaryurp/source/writer.cxx | |
parent | 6770fbe36b7268f3c900ed7188c5308dca6f3b13 (diff) |
sb138: #i116038# fresh implementation of binary URP bridge
Diffstat (limited to 'binaryurp/source/writer.cxx')
-rwxr-xr-x | binaryurp/source/writer.cxx | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/binaryurp/source/writer.cxx b/binaryurp/source/writer.cxx new file mode 100755 index 000000000000..439b7dba804a --- /dev/null +++ b/binaryurp/source/writer.cxx @@ -0,0 +1,475 @@ +/************************************************************************* +* +* 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 <vector> + +#include "com/sun/star/connection/XConnection.hpp" +#include "com/sun/star/lang/WrappedTargetRuntimeException.hpp" +#include "com/sun/star/uno/XCurrentContext.hpp" +#include "cppuhelper/exc_hlp.hxx" +#include "osl/mutex.hxx" +#include "rtl/memory.h" +#include "uno/dispatcher.hxx" + +#include "binaryany.hxx" +#include "bridge.hxx" +#include "currentcontext.hxx" +#include "specialfunctionids.hxx" +#include "writer.hxx" + +namespace binaryurp { + +namespace { + +namespace css = com::sun::star; + +bool isProtocolPropertyMessage(rtl::OUString const & oid) { + return oid.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties")); +} + +} + +Writer::Item::Item() {} + +Writer::Item::Item( + rtl::ByteSequence const & theTid, rtl::OUString const & theOid, + css::uno::TypeDescription const & theType, + css::uno::TypeDescription const & theMember, + std::vector< BinaryAny > const & inArguments, + css::uno::UnoInterfaceReference const & theCurrentContext): + request(true), tid(theTid), oid(theOid), type(theType), member(theMember), + arguments(inArguments), currentContext(theCurrentContext) +{} + +Writer::Item::Item( + rtl::ByteSequence const & theTid, + css::uno::TypeDescription const & theMember, bool theSetter, + bool theException, BinaryAny const & theReturnValue, + std::vector< BinaryAny > const & outArguments, + bool theSetCurrentContextMode): + request(false), tid(theTid), member(theMember), setter(theSetter), + arguments(outArguments), exception(theException), + returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode) +{} + +Writer::Writer(rtl::Reference< Bridge > const & bridge): + bridge_(bridge), marshal_(bridge, state_), stop_(false) +{ + OSL_ASSERT(bridge.is()); + acquire(); +} + +void Writer::sendDirectRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + css::uno::TypeDescription const & type, + css::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments) +{ + OSL_ASSERT(!unblocked_.check()); + sendRequest( + tid, oid, type, member, inArguments, false, + css::uno::UnoInterfaceReference()); +} + +void Writer::sendDirectReply( + rtl::ByteSequence const & tid, css::uno::TypeDescription const & member, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments) +{ + OSL_ASSERT(!unblocked_.check()); + sendReply(tid, member, false, exception, returnValue,outArguments); +} + +void Writer::queueRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + css::uno::TypeDescription const & type, + css::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments) +{ + css::uno::UnoInterfaceReference cc(current_context::get()); + osl::MutexGuard g(mutex_); + queue_.push_back(Item(tid, oid, type, member, inArguments, cc)); + items_.set(); +} + +void Writer::queueReply( + rtl::ByteSequence const & tid, + com::sun::star::uno::TypeDescription const & member, bool setter, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode) +{ + osl::MutexGuard g(mutex_); + queue_.push_back( + Item( + tid, member, setter, exception, returnValue, outArguments, + setCurrentContextMode)); + items_.set(); +} + +void Writer::unblock() { + // Assumes that osl::Condition::set works as a memory barrier, so that + // changes made by preceeding sendDirectRequest/Reply calls are visible to + // subsequent sendRequest/Reply calls: + unblocked_.set(); +} + +void Writer::stop() { + { + osl::MutexGuard g(mutex_); + stop_ = true; + } + unblocked_.set(); + items_.set(); +} + +Writer::~Writer() {} + +void Writer::run() { + try { + unblocked_.wait(); + for (;;) { + items_.wait(); + Item item; + { + osl::MutexGuard g(mutex_); + if (stop_) { + return; + } + OSL_ASSERT(!queue_.empty()); + item = queue_.front(); + queue_.pop_front(); + if (queue_.empty()) { + items_.reset(); + } + } + if (item.request) { + sendRequest( + item.tid, item.oid, item.type, item.member, item.arguments, + (!item.oid.equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM("UrpProtocolProperties")) && + !item.member.equals( + css::uno::TypeDescription( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.uno.XInterface::" + "release")))) && + bridge_->isCurrentContextMode()), + item.currentContext); + } else { + sendReply( + item.tid, item.member, item.setter, item.exception, + item.returnValue, item.arguments); + if (item.setCurrentContextMode) { + bridge_->setCurrentContextMode(); + } + } + } + } 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 Writer::onTerminated() { + release(); +} + +void Writer::sendRequest( + rtl::ByteSequence const & tid, rtl::OUString const & oid, + css::uno::TypeDescription const & type, + css::uno::TypeDescription const & member, + std::vector< BinaryAny > const & inArguments, bool currentContextMode, + css::uno::UnoInterfaceReference const & currentContext) +{ + OSL_ASSERT(tid.getLength() != 0 && oid.getLength() != 0 && member.is()); + css::uno::TypeDescription t(type); + sal_Int32 functionId = 0; + bool forceSynchronous = false; + member.makeComplete(); + switch (member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + { + typelib_InterfaceAttributeTypeDescription * atd = + reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >( + member.get()); + OSL_ASSERT(atd->pInterface != 0); + if (!t.is()) { + t = css::uno::TypeDescription(&atd->pInterface->aBase); + } + t.makeComplete(); + functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[ + atd->aBase.nPosition]; + if (!inArguments.empty()) { // setter + ++functionId; + } + break; + } + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( + member.get()); + OSL_ASSERT(mtd->pInterface != 0); + if (!t.is()) { + t = css::uno::TypeDescription(&mtd->pInterface->aBase); + } + t.makeComplete(); + functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[ + mtd->aBase.nPosition]; + forceSynchronous = mtd->bOneWay && + functionId != SPECIAL_FUNCTION_ID_RELEASE; + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + OSL_ASSERT(functionId >= 0); + if (functionId > SAL_MAX_UINT16) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("function ID too large for URP")), + css::uno::Reference< css::uno::XInterface >()); + } + std::vector< unsigned char > buf; + bool newType = !(lastType_.is() && t.equals(lastType_)); + bool newOid = oid != lastOid_; + bool newTid = tid != lastTid_; + if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF) + // > 14 bit function ID + { + Marshal::write8( + &buf, + (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) | + (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) | + (forceSynchronous ? 0x01 : 0))); + // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID, + // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS + if (forceSynchronous) { + Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS + } + if (functionId <= 0xFF) { + Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId)); + } else { + Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId)); + } + if (newType) { + marshal_.writeType(&buf, t); + } + if (newOid) { + marshal_.writeOid(&buf, oid); + } + if (newTid) { + marshal_.writeTid(&buf, tid); + } + } else if (functionId <= 0x3F) { // <= 6 bit function ID + Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId)); + // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14 + } else { + Marshal::write8( + &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8))); + // bit 7: !LONGHEADER, bit 6: FUNCTIONID14 + Marshal::write8(&buf, functionId & 0xFF); + } + if (currentContextMode) { + css::uno::UnoInterfaceReference cc(currentContext); + marshal_.writeValue( + &buf, + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< css::uno::XCurrentContext > >::get()), + BinaryAny( + css::uno::TypeDescription( + cppu::UnoType< + css::uno::Reference< + css::uno::XCurrentContext > >::get()), + &cc.m_pUnoI)); + } + switch (member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (!inArguments.empty()) { // setter + OSL_ASSERT(inArguments.size() == 1); + marshal_.writeValue( + &buf, + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member.get())-> + pAttributeTypeRef), + inArguments.front()); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< typelib_InterfaceMethodTypeDescription * >( + member.get()); + std::vector< BinaryAny >::const_iterator i(inArguments.begin()); + for (sal_Int32 j = 0; j != mtd->nParams; ++j) { + if (mtd->pParams[j].bIn) { + marshal_.writeValue( + &buf, + css::uno::TypeDescription(mtd->pParams[j].pTypeRef), + *i++); + } + } + OSL_ASSERT(i == inArguments.end()); + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + sendMessage(buf); + lastType_ = t; + lastOid_ = oid; + lastTid_ = tid; +} + +void Writer::sendReply( + rtl::ByteSequence const & tid, + com::sun::star::uno::TypeDescription const & member, bool setter, + bool exception, BinaryAny const & returnValue, + std::vector< BinaryAny > const & outArguments) +{ + OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete); + std::vector< unsigned char > buf; + bool newTid = tid != lastTid_; + Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0)); + // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID + if (newTid) { + marshal_.writeTid(&buf, tid); + } + if (exception) { + marshal_.writeValue( + &buf, + css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()), + returnValue); + } else { + switch (member.get()->eTypeClass) { + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + if (!setter) { + marshal_.writeValue( + &buf, + css::uno::TypeDescription( + reinterpret_cast< + typelib_InterfaceAttributeTypeDescription * >( + member.get())-> + pAttributeTypeRef), + returnValue); + } + break; + case typelib_TypeClass_INTERFACE_METHOD: + { + typelib_InterfaceMethodTypeDescription * mtd = + reinterpret_cast< + typelib_InterfaceMethodTypeDescription * >( + member.get()); + marshal_.writeValue( + &buf, css::uno::TypeDescription(mtd->pReturnTypeRef), + returnValue); + std::vector< BinaryAny >::const_iterator i( + outArguments.begin()); + for (sal_Int32 j = 0; j != mtd->nParams; ++j) { + if (mtd->pParams[j].bOut) { + marshal_.writeValue( + &buf, + css::uno::TypeDescription(mtd->pParams[j].pTypeRef), + *i++); + } + } + OSL_ASSERT(i == outArguments.end()); + break; + } + default: + OSL_ASSERT(false); // this cannot happen + break; + } + } + sendMessage(buf); + lastTid_ = tid; + bridge_->decrementCalls(); +} + +void Writer::sendMessage(std::vector< unsigned char > const & buffer) { + std::vector< unsigned char > header; + if (buffer.size() > SAL_MAX_UINT32) { + throw css::uno::RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("message too large for URP")), + css::uno::Reference< css::uno::XInterface >()); + } + Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size())); + Marshal::write32(&header, 1); + OSL_ASSERT(!buffer.empty()); + unsigned char const * p = &buffer[0]; + std::vector< unsigned char >::size_type n = buffer.size(); + OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE); + sal_Size k = SAL_MAX_INT32 - header.size(); + if (n < k) { + k = static_cast< sal_Size >(n); + } + css::uno::Sequence< sal_Int8 > s( + static_cast< sal_Int32 >(header.size() + k)); + OSL_ASSERT(!header.empty()); + rtl_copyMemory( + s.getArray(), &header[0], static_cast< sal_Size >(header.size())); + for (;;) { + rtl_copyMemory(s.getArray() + s.getLength() - k, p, k); + try { + bridge_->getConnection()->write(s); + } catch (css::io::IOException & e) { + css::uno::Any exc(cppu::getCaughtException()); + throw css::lang::WrappedTargetRuntimeException( + (rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "Binary URP write raised IO exception: ")) + + e.Message), + css::uno::Reference< css::uno::XInterface >(), exc); + } + n = static_cast< std::vector< unsigned char >::size_type >(n - k); + if (n == 0) { + break; + } + p += k; + k = SAL_MAX_INT32; + if (n < k) { + k = static_cast< sal_Size >(n); + } + s.realloc(k); + } +} + +} |