| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the 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.isEmpty() ) { |
| throw css::io::IOException( |
| rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM( |
| "binaryurp::Unmarshal: emtpy OID")), |
| css::uno::Reference< css::uno::XInterface >()); |
| } |
| lastOid_ = oid; |
| } else { |
| if ( lastOid_.isEmpty() ) { |
| 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_; |
| } |
| |
| } |