/************************************************************** * * 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 #include #include #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_; } }