summaryrefslogtreecommitdiff
path: root/binaryurp/source/reader.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'binaryurp/source/reader.cxx')
-rw-r--r--binaryurp/source/reader.cxx553
1 files changed, 553 insertions, 0 deletions
diff --git a/binaryurp/source/reader.cxx b/binaryurp/source/reader.cxx
new file mode 100644
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_;
+}
+
+}