LCOV - code coverage report
Current view: top level - binaryurp/source - writer.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 187 0.0 %
Date: 2014-04-14 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "sal/config.h"
      21             : 
      22             : #include <exception>
      23             : #include <vector>
      24             : #include <string.h>
      25             : 
      26             : #include "com/sun/star/connection/XConnection.hpp"
      27             : #include "com/sun/star/lang/WrappedTargetRuntimeException.hpp"
      28             : #include "com/sun/star/uno/XCurrentContext.hpp"
      29             : #include "cppuhelper/exc_hlp.hxx"
      30             : #include "osl/mutex.hxx"
      31             : #include "uno/dispatcher.hxx"
      32             : 
      33             : #include "binaryany.hxx"
      34             : #include "bridge.hxx"
      35             : #include "currentcontext.hxx"
      36             : #include "specialfunctionids.hxx"
      37             : #include "writer.hxx"
      38             : 
      39             : namespace binaryurp {
      40             : 
      41           0 : Writer::Item::Item() {}
      42             : 
      43           0 : Writer::Item::Item(
      44             :     rtl::ByteSequence const & theTid, OUString const & theOid,
      45             :     css::uno::TypeDescription const & theType,
      46             :     css::uno::TypeDescription const & theMember,
      47             :     std::vector< BinaryAny > const & inArguments,
      48             :     css::uno::UnoInterfaceReference const & theCurrentContext):
      49             :     request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
      50           0 :     arguments(inArguments), currentContext(theCurrentContext)
      51           0 : {}
      52             : 
      53           0 : Writer::Item::Item(
      54             :     rtl::ByteSequence const & theTid,
      55             :     css::uno::TypeDescription const & theMember, bool theSetter,
      56             :     bool theException, BinaryAny const & theReturnValue,
      57             :     std::vector< BinaryAny > const & outArguments,
      58             :     bool theSetCurrentContextMode):
      59             :     request(false), tid(theTid), member(theMember), setter(theSetter),
      60             :     arguments(outArguments), exception(theException),
      61           0 :     returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
      62           0 : {}
      63             : 
      64           0 : Writer::Writer(rtl::Reference< Bridge > const  & bridge):
      65             :     Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
      66           0 :     stop_(false)
      67             : {
      68             :     OSL_ASSERT(bridge.is());
      69           0 : }
      70             : 
      71           0 : void Writer::sendDirectRequest(
      72             :     rtl::ByteSequence const & tid, OUString const & oid,
      73             :     css::uno::TypeDescription const & type,
      74             :     css::uno::TypeDescription const & member,
      75             :     std::vector< BinaryAny > const & inArguments)
      76             : {
      77             :     OSL_ASSERT(!unblocked_.check());
      78             :     sendRequest(
      79             :         tid, oid, type, member, inArguments, false,
      80           0 :         css::uno::UnoInterfaceReference());
      81           0 : }
      82             : 
      83           0 : void Writer::sendDirectReply(
      84             :     rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
      85             :     bool exception, BinaryAny const & returnValue,
      86             :     std::vector< BinaryAny > const & outArguments)
      87             : {
      88             :     OSL_ASSERT(!unblocked_.check());
      89           0 :     sendReply(tid, member, false, exception, returnValue,outArguments);
      90           0 : }
      91             : 
      92           0 : void Writer::queueRequest(
      93             :     rtl::ByteSequence const & tid, OUString const & oid,
      94             :     css::uno::TypeDescription const & type,
      95             :     css::uno::TypeDescription const & member,
      96             :     std::vector< BinaryAny > const & inArguments)
      97             : {
      98           0 :     css::uno::UnoInterfaceReference cc(current_context::get());
      99           0 :     osl::MutexGuard g(mutex_);
     100           0 :     queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
     101           0 :     items_.set();
     102           0 : }
     103             : 
     104           0 : void Writer::queueReply(
     105             :     rtl::ByteSequence const & tid,
     106             :     com::sun::star::uno::TypeDescription const & member, bool setter,
     107             :     bool exception, BinaryAny const & returnValue,
     108             :     std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode)
     109             : {
     110           0 :     osl::MutexGuard g(mutex_);
     111             :     queue_.push_back(
     112             :         Item(
     113             :             tid, member, setter, exception, returnValue, outArguments,
     114           0 :             setCurrentContextMode));
     115           0 :     items_.set();
     116           0 : }
     117             : 
     118           0 : void Writer::unblock() {
     119             :     // Assumes that osl::Condition::set works as a memory barrier, so that
     120             :     // changes made by preceeding sendDirectRequest/Reply calls are visible to
     121             :     // subsequent sendRequest/Reply calls:
     122           0 :     unblocked_.set();
     123           0 : }
     124             : 
     125           0 : void Writer::stop() {
     126             :     {
     127           0 :         osl::MutexGuard g(mutex_);
     128           0 :         stop_ = true;
     129             :     }
     130           0 :     unblocked_.set();
     131           0 :     items_.set();
     132           0 : }
     133             : 
     134           0 : Writer::~Writer() {}
     135             : 
     136           0 : void Writer::execute() {
     137             :     try {
     138           0 :         unblocked_.wait();
     139             :         for (;;) {
     140           0 :             items_.wait();
     141           0 :             Item item;
     142             :             {
     143           0 :                 osl::MutexGuard g(mutex_);
     144           0 :                 if (stop_) {
     145           0 :                     return;
     146             :                 }
     147             :                 OSL_ASSERT(!queue_.empty());
     148           0 :                 item = queue_.front();
     149           0 :                 queue_.pop_front();
     150           0 :                 if (queue_.empty()) {
     151           0 :                     items_.reset();
     152           0 :                 }
     153             :             }
     154           0 :             if (item.request) {
     155             :                 sendRequest(
     156             :                     item.tid, item.oid, item.type, item.member, item.arguments,
     157           0 :                     (item.oid != "UrpProtocolProperties" &&
     158             :                      !item.member.equals(
     159             :                          css::uno::TypeDescription(
     160           0 :                              "com.sun.star.uno.XInterface::release")) &&
     161           0 :                      bridge_->isCurrentContextMode()),
     162           0 :                     item.currentContext);
     163             :             } else {
     164             :                 sendReply(
     165             :                     item.tid, item.member, item.setter, item.exception,
     166           0 :                     item.returnValue, item.arguments);
     167           0 :                 if (item.setCurrentContextMode) {
     168           0 :                     bridge_->setCurrentContextMode();
     169             :                 }
     170             :             }
     171           0 :         }
     172           0 :     } catch (const css::uno::Exception & e) {
     173             :         OSL_TRACE(
     174             :             OSL_LOG_PREFIX "caught UNO exception '%s'",
     175             :             OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
     176           0 :     } catch (const std::exception & e) {
     177             :         OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
     178             :     }
     179           0 :     bridge_->terminate(false);
     180           0 :     bridge_.clear();
     181             : }
     182             : 
     183           0 : void Writer::sendRequest(
     184             :     rtl::ByteSequence const & tid, OUString const & oid,
     185             :     css::uno::TypeDescription const & type,
     186             :     css::uno::TypeDescription const & member,
     187             :     std::vector< BinaryAny > const & inArguments, bool currentContextMode,
     188             :     css::uno::UnoInterfaceReference const & currentContext)
     189             : {
     190             :     OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
     191           0 :     css::uno::TypeDescription t(type);
     192           0 :     sal_Int32 functionId = 0;
     193           0 :     bool forceSynchronous = false;
     194           0 :     member.makeComplete();
     195           0 :     switch (member.get()->eTypeClass) {
     196             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     197             :         {
     198             :             typelib_InterfaceAttributeTypeDescription * atd =
     199             :                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
     200           0 :                     member.get());
     201             :             OSL_ASSERT(atd->pInterface != 0);
     202           0 :             if (!t.is()) {
     203           0 :                 t = css::uno::TypeDescription(&atd->pInterface->aBase);
     204             :             }
     205           0 :             t.makeComplete();
     206             :             functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
     207           0 :                 atd->aBase.nPosition];
     208           0 :             if (!inArguments.empty()) { // setter
     209           0 :                 ++functionId;
     210             :             }
     211           0 :             break;
     212             :         }
     213             :     case typelib_TypeClass_INTERFACE_METHOD:
     214             :         {
     215             :             typelib_InterfaceMethodTypeDescription * mtd =
     216             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     217           0 :                     member.get());
     218             :             OSL_ASSERT(mtd->pInterface != 0);
     219           0 :             if (!t.is()) {
     220           0 :                 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
     221             :             }
     222           0 :             t.makeComplete();
     223             :             functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
     224           0 :                 mtd->aBase.nPosition];
     225           0 :             forceSynchronous = mtd->bOneWay &&
     226           0 :                 functionId != SPECIAL_FUNCTION_ID_RELEASE;
     227           0 :             break;
     228             :         }
     229             :     default:
     230             :         OSL_ASSERT(false); // this cannot happen
     231           0 :         break;
     232             :     }
     233             :     OSL_ASSERT(functionId >= 0);
     234           0 :     if (functionId > SAL_MAX_UINT16) {
     235             :         throw css::uno::RuntimeException(
     236             :             "function ID too large for URP",
     237           0 :             css::uno::Reference< css::uno::XInterface >());
     238             :     }
     239           0 :     std::vector< unsigned char > buf;
     240           0 :     bool newType = !(lastType_.is() && t.equals(lastType_));
     241           0 :     bool newOid = oid != lastOid_;
     242           0 :     bool newTid = tid != lastTid_;
     243           0 :     if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
     244             :         // > 14 bit function ID
     245             :     {
     246             :         Marshal::write8(
     247             :             &buf,
     248             :             (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
     249             :              (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
     250           0 :              (forceSynchronous ? 0x01 : 0)));
     251             :             // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
     252             :             // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
     253           0 :         if (forceSynchronous) {
     254           0 :             Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
     255             :         }
     256           0 :         if (functionId <= 0xFF) {
     257           0 :             Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
     258             :         } else {
     259           0 :             Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
     260             :         }
     261           0 :         if (newType) {
     262           0 :             marshal_.writeType(&buf, t);
     263             :         }
     264           0 :         if (newOid) {
     265           0 :             marshal_.writeOid(&buf, oid);
     266             :         }
     267           0 :         if (newTid) {
     268           0 :             marshal_.writeTid(&buf, tid);
     269             :         }
     270           0 :     } else if (functionId <= 0x3F) { // <= 6 bit function ID
     271           0 :         Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
     272             :             // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
     273             :     } else {
     274             :         Marshal::write8(
     275           0 :             &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
     276             :             // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
     277           0 :         Marshal::write8(&buf, functionId & 0xFF);
     278             :     }
     279           0 :     if (currentContextMode) {
     280           0 :         css::uno::UnoInterfaceReference cc(currentContext);
     281             :         marshal_.writeValue(
     282             :             &buf,
     283             :             css::uno::TypeDescription(
     284             :                 cppu::UnoType<
     285           0 :                     css::uno::Reference< css::uno::XCurrentContext > >::get()),
     286             :             BinaryAny(
     287             :                 css::uno::TypeDescription(
     288             :                     cppu::UnoType<
     289             :                         css::uno::Reference<
     290           0 :                             css::uno::XCurrentContext > >::get()),
     291           0 :                 &cc.m_pUnoI));
     292             :     }
     293           0 :     switch (member.get()->eTypeClass) {
     294             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     295           0 :         if (!inArguments.empty()) { // setter
     296             :             OSL_ASSERT(inArguments.size() == 1);
     297             :             marshal_.writeValue(
     298             :                 &buf,
     299             :                 css::uno::TypeDescription(
     300             :                     reinterpret_cast<
     301             :                         typelib_InterfaceAttributeTypeDescription * >(
     302           0 :                             member.get())->
     303             :                     pAttributeTypeRef),
     304           0 :                 inArguments.front());
     305             :         }
     306           0 :         break;
     307             :     case typelib_TypeClass_INTERFACE_METHOD:
     308             :         {
     309             :             typelib_InterfaceMethodTypeDescription * mtd =
     310             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     311           0 :                     member.get());
     312           0 :             std::vector< BinaryAny >::const_iterator i(inArguments.begin());
     313           0 :             for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     314           0 :                 if (mtd->pParams[j].bIn) {
     315             :                     marshal_.writeValue(
     316             :                         &buf,
     317           0 :                         css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     318           0 :                         *i++);
     319             :                 }
     320             :             }
     321             :             OSL_ASSERT(i == inArguments.end());
     322           0 :             break;
     323             :         }
     324             :     default:
     325             :         OSL_ASSERT(false); // this cannot happen
     326           0 :         break;
     327             :     }
     328           0 :     sendMessage(buf);
     329           0 :     lastType_ = t;
     330           0 :     lastOid_ = oid;
     331           0 :     lastTid_ = tid;
     332           0 : }
     333             : 
     334           0 : void Writer::sendReply(
     335             :     rtl::ByteSequence const & tid,
     336             :     com::sun::star::uno::TypeDescription const & member, bool setter,
     337             :     bool exception, BinaryAny const & returnValue,
     338             :     std::vector< BinaryAny > const & outArguments)
     339             : {
     340             :     OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
     341           0 :     std::vector< unsigned char > buf;
     342           0 :     bool newTid = tid != lastTid_;
     343           0 :     Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
     344             :         // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
     345           0 :     if (newTid) {
     346           0 :         marshal_.writeTid(&buf, tid);
     347             :     }
     348           0 :     if (exception) {
     349             :         marshal_.writeValue(
     350             :             &buf,
     351           0 :             css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
     352           0 :             returnValue);
     353             :     } else {
     354           0 :         switch (member.get()->eTypeClass) {
     355             :         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     356           0 :             if (!setter) {
     357             :                 marshal_.writeValue(
     358             :                     &buf,
     359             :                     css::uno::TypeDescription(
     360             :                         reinterpret_cast<
     361             :                             typelib_InterfaceAttributeTypeDescription * >(
     362           0 :                                 member.get())->
     363             :                         pAttributeTypeRef),
     364           0 :                     returnValue);
     365             :             }
     366           0 :             break;
     367             :         case typelib_TypeClass_INTERFACE_METHOD:
     368             :             {
     369             :                 typelib_InterfaceMethodTypeDescription * mtd =
     370             :                     reinterpret_cast<
     371             :                         typelib_InterfaceMethodTypeDescription * >(
     372           0 :                             member.get());
     373             :                 marshal_.writeValue(
     374             :                     &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
     375           0 :                     returnValue);
     376             :                 std::vector< BinaryAny >::const_iterator i(
     377           0 :                     outArguments.begin());
     378           0 :                 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     379           0 :                     if (mtd->pParams[j].bOut) {
     380             :                         marshal_.writeValue(
     381             :                             &buf,
     382           0 :                             css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     383           0 :                             *i++);
     384             :                     }
     385             :                 }
     386             :                 OSL_ASSERT(i == outArguments.end());
     387           0 :                 break;
     388             :             }
     389             :         default:
     390             :             OSL_ASSERT(false); // this cannot happen
     391           0 :             break;
     392             :         }
     393             :     }
     394           0 :     sendMessage(buf);
     395           0 :     lastTid_ = tid;
     396           0 :     bridge_->decrementCalls();
     397           0 : }
     398             : 
     399           0 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
     400           0 :     std::vector< unsigned char > header;
     401           0 :     if (buffer.size() > SAL_MAX_UINT32) {
     402             :         throw css::uno::RuntimeException(
     403             :             "message too large for URP",
     404           0 :             css::uno::Reference< css::uno::XInterface >());
     405             :     }
     406           0 :     Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
     407           0 :     Marshal::write32(&header, 1);
     408             :     OSL_ASSERT(!buffer.empty());
     409           0 :     unsigned char const * p = &buffer[0];
     410           0 :     std::vector< unsigned char >::size_type n = buffer.size();
     411             :     OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
     412           0 :     sal_Size k = SAL_MAX_INT32 - header.size();
     413           0 :     if (n < k) {
     414           0 :         k = static_cast< sal_Size >(n);
     415             :     }
     416             :     css::uno::Sequence< sal_Int8 > s(
     417           0 :         static_cast< sal_Int32 >(header.size() + k));
     418             :     OSL_ASSERT(!header.empty());
     419             :     memcpy(
     420           0 :         s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
     421             :     for (;;) {
     422           0 :         memcpy(s.getArray() + s.getLength() - k, p, k);
     423             :         try {
     424           0 :             bridge_->getConnection()->write(s);
     425           0 :         } catch (const css::io::IOException & e) {
     426           0 :             css::uno::Any exc(cppu::getCaughtException());
     427             :             throw css::lang::WrappedTargetRuntimeException(
     428           0 :                 "Binary URP write raised IO exception: " + e.Message,
     429           0 :                 css::uno::Reference< css::uno::XInterface >(), exc);
     430             :         }
     431           0 :         n = static_cast< std::vector< unsigned char >::size_type >(n - k);
     432           0 :         if (n == 0) {
     433           0 :             break;
     434             :         }
     435           0 :         p += k;
     436           0 :         k = SAL_MAX_INT32;
     437           0 :         if (n < k) {
     438           0 :             k = static_cast< sal_Size >(n);
     439             :         }
     440           0 :         s.realloc(k);
     441           0 :     }
     442           0 : }
     443             : 
     444             : }
     445             : 
     446             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10