9201704ede
Part IV Module basic (small fix per demand from Ivan Timofeev) binaryurp bridges
474 lines
16 KiB
C++
474 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* 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;
|
|
|
|
}
|
|
|
|
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() {
|
|
setName("binaryurpWriter");
|
|
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 (const css::uno::Exception & e) {
|
|
OSL_TRACE(
|
|
OSL_LOG_PREFIX "caught UNO exception '%s'",
|
|
rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
|
|
} catch (const 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.isEmpty() && 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 (const 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);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|