LCOV - code coverage report
Current view: top level - binaryurp/source - writer.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 163 189 86.2 %
Date: 2014-11-03 Functions: 16 16 100.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      415785 : Writer::Item::Item()
      42             :     : request(false)
      43             :     , setter(false)
      44             :     , exception(false)
      45      415785 :     , setCurrentContextMode(false)
      46      415785 : {}
      47             : 
      48       23761 : Writer::Item::Item(
      49             :     rtl::ByteSequence const & theTid, OUString const & theOid,
      50             :     css::uno::TypeDescription const & theType,
      51             :     css::uno::TypeDescription const & theMember,
      52             :     std::vector< BinaryAny > const & inArguments,
      53             :     css::uno::UnoInterfaceReference const & theCurrentContext):
      54             :     request(true), tid(theTid), oid(theOid), type(theType), member(theMember),
      55             :     setter(false), arguments(inArguments), exception(false),
      56       23761 :     currentContext(theCurrentContext), setCurrentContextMode(false)
      57       23761 : {}
      58             : 
      59      391926 : Writer::Item::Item(
      60             :     rtl::ByteSequence const & theTid,
      61             :     css::uno::TypeDescription const & theMember, bool theSetter,
      62             :     bool theException, BinaryAny const & theReturnValue,
      63             :     std::vector< BinaryAny > const & outArguments,
      64             :     bool theSetCurrentContextMode):
      65             :     request(false), tid(theTid), member(theMember), setter(theSetter),
      66             :     arguments(outArguments), exception(theException),
      67      391926 :     returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
      68      391926 : {}
      69             : 
      70         102 : Writer::Writer(rtl::Reference< Bridge > const  & bridge):
      71             :     Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
      72         102 :     stop_(false)
      73             : {
      74             :     OSL_ASSERT(bridge.is());
      75         102 : }
      76             : 
      77         165 : void Writer::sendDirectRequest(
      78             :     rtl::ByteSequence const & tid, OUString const & oid,
      79             :     css::uno::TypeDescription const & type,
      80             :     css::uno::TypeDescription const & member,
      81             :     std::vector< BinaryAny > const & inArguments)
      82             : {
      83             :     OSL_ASSERT(!unblocked_.check());
      84             :     sendRequest(
      85             :         tid, oid, type, member, inArguments, false,
      86         165 :         css::uno::UnoInterfaceReference());
      87         165 : }
      88             : 
      89         141 : void Writer::sendDirectReply(
      90             :     rtl::ByteSequence const & tid, css::uno::TypeDescription const & member,
      91             :     bool exception, BinaryAny const & returnValue,
      92             :     std::vector< BinaryAny > const & outArguments)
      93             : {
      94             :     OSL_ASSERT(!unblocked_.check());
      95         141 :     sendReply(tid, member, false, exception, returnValue,outArguments);
      96         141 : }
      97             : 
      98       23761 : void Writer::queueRequest(
      99             :     rtl::ByteSequence const & tid, OUString const & oid,
     100             :     css::uno::TypeDescription const & type,
     101             :     css::uno::TypeDescription const & member,
     102             :     std::vector< BinaryAny > const & inArguments)
     103             : {
     104       23761 :     css::uno::UnoInterfaceReference cc(current_context::get());
     105       47522 :     osl::MutexGuard g(mutex_);
     106       23761 :     queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
     107       47522 :     items_.set();
     108       23761 : }
     109             : 
     110      391926 : void Writer::queueReply(
     111             :     rtl::ByteSequence const & tid,
     112             :     com::sun::star::uno::TypeDescription const & member, bool setter,
     113             :     bool exception, BinaryAny const & returnValue,
     114             :     std::vector< BinaryAny > const & outArguments, bool setCurrentContextMode)
     115             : {
     116      391926 :     osl::MutexGuard g(mutex_);
     117             :     queue_.push_back(
     118             :         Item(
     119             :             tid, member, setter, exception, returnValue, outArguments,
     120      391926 :             setCurrentContextMode));
     121      391926 :     items_.set();
     122      391926 : }
     123             : 
     124         102 : void Writer::unblock() {
     125             :     // Assumes that osl::Condition::set works as a memory barrier, so that
     126             :     // changes made by preceding sendDirectRequest/Reply calls are visible to
     127             :     // subsequent sendRequest/Reply calls:
     128         102 :     unblocked_.set();
     129         102 : }
     130             : 
     131         102 : void Writer::stop() {
     132             :     {
     133         102 :         osl::MutexGuard g(mutex_);
     134         102 :         stop_ = true;
     135             :     }
     136         102 :     unblocked_.set();
     137         102 :     items_.set();
     138         102 : }
     139             : 
     140         204 : Writer::~Writer() {}
     141             : 
     142         102 : void Writer::execute() {
     143             :     try {
     144         102 :         unblocked_.wait();
     145             :         for (;;) {
     146      415785 :             items_.wait();
     147      415785 :             Item item;
     148             :             {
     149      415785 :                 osl::MutexGuard g(mutex_);
     150      415785 :                 if (stop_) {
     151         204 :                     return;
     152             :                 }
     153             :                 OSL_ASSERT(!queue_.empty());
     154      415683 :                 item = queue_.front();
     155      415683 :                 queue_.pop_front();
     156      415683 :                 if (queue_.empty()) {
     157      413399 :                     items_.reset();
     158      415683 :                 }
     159             :             }
     160      415683 :             if (item.request) {
     161             :                 sendRequest(
     162             :                     item.tid, item.oid, item.type, item.member, item.arguments,
     163       71271 :                     (item.oid != "UrpProtocolProperties" &&
     164             :                      !item.member.equals(
     165             :                          css::uno::TypeDescription(
     166      132927 :                              "com.sun.star.uno.XInterface::release")) &&
     167       14142 :                      bridge_->isCurrentContextMode()),
     168       23757 :                     item.currentContext);
     169             :             } else {
     170             :                 sendReply(
     171             :                     item.tid, item.member, item.setter, item.exception,
     172      391926 :                     item.returnValue, item.arguments);
     173      391926 :                 if (item.setCurrentContextMode) {
     174           0 :                     bridge_->setCurrentContextMode();
     175             :                 }
     176             :             }
     177      415683 :         }
     178           0 :     } catch (const css::uno::Exception & e) {
     179             :         OSL_TRACE(
     180             :             "caught UNO exception '%s'",
     181             :             OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
     182           0 :     } catch (const std::exception & e) {
     183             :         OSL_TRACE("caught C++ exception '%s'", e.what());
     184             :     }
     185           0 :     bridge_->terminate(false);
     186           0 :     bridge_.clear();
     187             : }
     188             : 
     189       23922 : void Writer::sendRequest(
     190             :     rtl::ByteSequence const & tid, OUString const & oid,
     191             :     css::uno::TypeDescription const & type,
     192             :     css::uno::TypeDescription const & member,
     193             :     std::vector< BinaryAny > const & inArguments, bool currentContextMode,
     194             :     css::uno::UnoInterfaceReference const & currentContext)
     195             : {
     196             :     OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
     197       23922 :     css::uno::TypeDescription t(type);
     198       23922 :     sal_Int32 functionId = 0;
     199       23922 :     bool forceSynchronous = false;
     200       23922 :     member.makeComplete();
     201       23922 :     switch (member.get()->eTypeClass) {
     202             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     203             :         {
     204             :             typelib_InterfaceAttributeTypeDescription * atd =
     205             :                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
     206        1799 :                     member.get());
     207             :             OSL_ASSERT(atd->pInterface != 0);
     208        1799 :             if (!t.is()) {
     209        1799 :                 t = css::uno::TypeDescription(&atd->pInterface->aBase);
     210             :             }
     211        1799 :             t.makeComplete();
     212             :             functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
     213        1799 :                 atd->aBase.nPosition];
     214        1799 :             if (!inArguments.empty()) { // setter
     215           0 :                 ++functionId;
     216             :             }
     217        1799 :             break;
     218             :         }
     219             :     case typelib_TypeClass_INTERFACE_METHOD:
     220             :         {
     221             :             typelib_InterfaceMethodTypeDescription * mtd =
     222             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     223       22123 :                     member.get());
     224             :             assert(mtd->pInterface != 0);
     225       22123 :             if (!t.is()) {
     226       12343 :                 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
     227             :             }
     228       22123 :             t.makeComplete();
     229             :             functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
     230       22123 :                 mtd->aBase.nPosition];
     231       22123 :             forceSynchronous = mtd->bOneWay &&
     232       22123 :                 functionId != SPECIAL_FUNCTION_ID_RELEASE;
     233       22123 :             break;
     234             :         }
     235             :     default:
     236             :         OSL_ASSERT(false); // this cannot happen
     237           0 :         break;
     238             :     }
     239             :     OSL_ASSERT(functionId >= 0);
     240       23922 :     if (functionId > SAL_MAX_UINT16) {
     241           0 :         throw css::uno::RuntimeException("function ID too large for URP");
     242             :     }
     243       23922 :     std::vector< unsigned char > buf;
     244       23922 :     bool newType = !(lastType_.is() && t.equals(lastType_));
     245       23922 :     bool newOid = oid != lastOid_;
     246       23922 :     bool newTid = tid != lastTid_;
     247       23922 :     if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
     248             :         // > 14 bit function ID
     249             :     {
     250             :         Marshal::write8(
     251             :             &buf,
     252             :             (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
     253             :              (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
     254       11288 :              (forceSynchronous ? 0x01 : 0)));
     255             :             // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
     256             :             // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
     257       11288 :         if (forceSynchronous) {
     258           0 :             Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
     259             :         }
     260       11288 :         if (functionId <= 0xFF) {
     261       11288 :             Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
     262             :         } else {
     263           0 :             Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
     264             :         }
     265       11288 :         if (newType) {
     266        3594 :             marshal_.writeType(&buf, t);
     267             :         }
     268       11288 :         if (newOid) {
     269        4534 :             marshal_.writeOid(&buf, oid);
     270             :         }
     271       22576 :         if (newTid) {
     272        6390 :             marshal_.writeTid(&buf, tid);
     273             :         }
     274       12634 :     } else if (functionId <= 0x3F) { // <= 6 bit function ID
     275       12634 :         Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
     276             :             // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
     277             :     } else {
     278             :         Marshal::write8(
     279           0 :             &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
     280             :             // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
     281           0 :         Marshal::write8(&buf, functionId & 0xFF);
     282             :     }
     283       23922 :     if (currentContextMode) {
     284       14142 :         css::uno::UnoInterfaceReference cc(currentContext);
     285             :         marshal_.writeValue(
     286             :             &buf,
     287             :             css::uno::TypeDescription(
     288             :                 cppu::UnoType<
     289       14142 :                     css::uno::Reference< css::uno::XCurrentContext > >::get()),
     290             :             BinaryAny(
     291             :                 css::uno::TypeDescription(
     292             :                     cppu::UnoType<
     293             :                         css::uno::Reference<
     294       14142 :                             css::uno::XCurrentContext > >::get()),
     295       28284 :                 &cc.m_pUnoI));
     296             :     }
     297       23922 :     switch (member.get()->eTypeClass) {
     298             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     299        1799 :         if (!inArguments.empty()) { // setter
     300             :             OSL_ASSERT(inArguments.size() == 1);
     301             :             marshal_.writeValue(
     302             :                 &buf,
     303             :                 css::uno::TypeDescription(
     304             :                     reinterpret_cast<
     305             :                         typelib_InterfaceAttributeTypeDescription * >(
     306           0 :                             member.get())->
     307             :                     pAttributeTypeRef),
     308           0 :                 inArguments.front());
     309             :         }
     310        1799 :         break;
     311             :     case typelib_TypeClass_INTERFACE_METHOD:
     312             :         {
     313             :             typelib_InterfaceMethodTypeDescription * mtd =
     314             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     315       22123 :                     member.get());
     316       22123 :             std::vector< BinaryAny >::const_iterator i(inArguments.begin());
     317       34005 :             for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     318       11882 :                 if (mtd->pParams[j].bIn) {
     319             :                     marshal_.writeValue(
     320             :                         &buf,
     321       11868 :                         css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     322       23736 :                         *i++);
     323             :                 }
     324             :             }
     325             :             OSL_ASSERT(i == inArguments.end());
     326       22123 :             break;
     327             :         }
     328             :     default:
     329             :         OSL_ASSERT(false); // this cannot happen
     330           0 :         break;
     331             :     }
     332       23922 :     sendMessage(buf);
     333       23922 :     lastType_ = t;
     334       23922 :     lastOid_ = oid;
     335       23922 :     lastTid_ = tid;
     336       23922 : }
     337             : 
     338      392067 : void Writer::sendReply(
     339             :     rtl::ByteSequence const & tid,
     340             :     com::sun::star::uno::TypeDescription const & member, bool setter,
     341             :     bool exception, BinaryAny const & returnValue,
     342             :     std::vector< BinaryAny > const & outArguments)
     343             : {
     344             :     OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
     345      392067 :     std::vector< unsigned char > buf;
     346      392067 :     bool newTid = tid != lastTid_;
     347      392067 :     Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
     348             :         // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
     349      392067 :     if (newTid) {
     350        6226 :         marshal_.writeTid(&buf, tid);
     351             :     }
     352      392067 :     if (exception) {
     353             :         marshal_.writeValue(
     354             :             &buf,
     355        1966 :             css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
     356        1966 :             returnValue);
     357             :     } else {
     358      390101 :         switch (member.get()->eTypeClass) {
     359             :         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     360        8002 :             if (!setter) {
     361             :                 marshal_.writeValue(
     362             :                     &buf,
     363             :                     css::uno::TypeDescription(
     364             :                         reinterpret_cast<
     365             :                             typelib_InterfaceAttributeTypeDescription * >(
     366        7580 :                                 member.get())->
     367             :                         pAttributeTypeRef),
     368        7580 :                     returnValue);
     369             :             }
     370        8002 :             break;
     371             :         case typelib_TypeClass_INTERFACE_METHOD:
     372             :             {
     373             :                 typelib_InterfaceMethodTypeDescription * mtd =
     374             :                     reinterpret_cast<
     375             :                         typelib_InterfaceMethodTypeDescription * >(
     376      382099 :                             member.get());
     377             :                 marshal_.writeValue(
     378             :                     &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
     379      382099 :                     returnValue);
     380             :                 std::vector< BinaryAny >::const_iterator i(
     381      382099 :                     outArguments.begin());
     382      698771 :                 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     383      316672 :                     if (mtd->pParams[j].bOut) {
     384             :                         marshal_.writeValue(
     385             :                             &buf,
     386         202 :                             css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     387         404 :                             *i++);
     388             :                     }
     389             :                 }
     390             :                 OSL_ASSERT(i == outArguments.end());
     391      382099 :                 break;
     392             :             }
     393             :         default:
     394             :             OSL_ASSERT(false); // this cannot happen
     395           0 :             break;
     396             :         }
     397             :     }
     398      392067 :     sendMessage(buf);
     399      392067 :     lastTid_ = tid;
     400      392067 :     bridge_->decrementCalls();
     401      392067 : }
     402             : 
     403      415989 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
     404      415989 :     std::vector< unsigned char > header;
     405      415989 :     if (buffer.size() > SAL_MAX_UINT32) {
     406             :         throw css::uno::RuntimeException(
     407           0 :             "message too large for URP");
     408             :     }
     409      415989 :     Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
     410      415989 :     Marshal::write32(&header, 1);
     411             :     OSL_ASSERT(!buffer.empty());
     412      415989 :     unsigned char const * p = &buffer[0];
     413      415989 :     std::vector< unsigned char >::size_type n = buffer.size();
     414             :     OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
     415      415989 :     sal_Size k = SAL_MAX_INT32 - header.size();
     416      415989 :     if (n < k) {
     417      415989 :         k = static_cast< sal_Size >(n);
     418             :     }
     419             :     css::uno::Sequence< sal_Int8 > s(
     420      831978 :         static_cast< sal_Int32 >(header.size() + k));
     421             :     OSL_ASSERT(!header.empty());
     422             :     memcpy(
     423      415989 :         s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
     424             :     for (;;) {
     425      415989 :         memcpy(s.getArray() + s.getLength() - k, p, k);
     426             :         try {
     427      415989 :             bridge_->getConnection()->write(s);
     428           0 :         } catch (const css::io::IOException & e) {
     429           0 :             css::uno::Any exc(cppu::getCaughtException());
     430             :             throw css::lang::WrappedTargetRuntimeException(
     431           0 :                 "Binary URP write raised IO exception: " + e.Message,
     432           0 :                 css::uno::Reference< css::uno::XInterface >(), exc);
     433             :         }
     434      415989 :         n = static_cast< std::vector< unsigned char >::size_type >(n - k);
     435      415989 :         if (n == 0) {
     436      415989 :             break;
     437             :         }
     438           0 :         p += k;
     439           0 :         k = SAL_MAX_INT32;
     440           0 :         if (n < k) {
     441           0 :             k = static_cast< sal_Size >(n);
     442             :         }
     443           0 :         s.realloc(k);
     444      415989 :     }
     445      415989 : }
     446             : 
     447             : }
     448             : 
     449             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10