LCOV - code coverage report
Current view: top level - binaryurp/source - writer.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 163 189 86.2 %
Date: 2015-06-13 12:38:46 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      219282 : Writer::Item::Item()
      42             :     : request(false)
      43             :     , setter(false)
      44             :     , exception(false)
      45      219282 :     , setCurrentContextMode(false)
      46      219282 : {}
      47             : 
      48       11879 : 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       11879 :     currentContext(theCurrentContext), setCurrentContextMode(false)
      57       11879 : {}
      58             : 
      59      207339 : 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      207339 :     returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
      68      207339 : {}
      69             : 
      70          66 : Writer::Writer(rtl::Reference< Bridge > const  & bridge):
      71             :     Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
      72          66 :     stop_(false)
      73             : {
      74             :     OSL_ASSERT(bridge.is());
      75          66 : }
      76             : 
      77         103 : 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         103 :         css::uno::UnoInterfaceReference());
      87         103 : }
      88             : 
      89          95 : 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          95 :     sendReply(tid, member, false, exception, returnValue,outArguments);
      96          95 : }
      97             : 
      98       11879 : 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       11879 :     css::uno::UnoInterfaceReference cc(current_context::get());
     105       23758 :     osl::MutexGuard g(mutex_);
     106       11879 :     queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
     107       23758 :     items_.set();
     108       11879 : }
     109             : 
     110      207339 : 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      207339 :     osl::MutexGuard g(mutex_);
     117             :     queue_.push_back(
     118             :         Item(
     119             :             tid, member, setter, exception, returnValue, outArguments,
     120      207339 :             setCurrentContextMode));
     121      207339 :     items_.set();
     122      207339 : }
     123             : 
     124          66 : 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          66 :     unblocked_.set();
     129          66 : }
     130             : 
     131          66 : void Writer::stop() {
     132             :     {
     133          66 :         osl::MutexGuard g(mutex_);
     134          66 :         stop_ = true;
     135             :     }
     136          66 :     unblocked_.set();
     137          66 :     items_.set();
     138          66 : }
     139             : 
     140         132 : Writer::~Writer() {}
     141             : 
     142          66 : void Writer::execute() {
     143             :     try {
     144          66 :         unblocked_.wait();
     145             :         for (;;) {
     146      219282 :             items_.wait();
     147      219282 :             Item item;
     148             :             {
     149      219282 :                 osl::MutexGuard g(mutex_);
     150      219282 :                 if (stop_) {
     151         132 :                     return;
     152             :                 }
     153             :                 OSL_ASSERT(!queue_.empty());
     154      219216 :                 item = queue_.front();
     155      219216 :                 queue_.pop_front();
     156      219216 :                 if (queue_.empty()) {
     157      216558 :                     items_.reset();
     158      219216 :                 }
     159             :             }
     160      219216 :             if (item.request) {
     161             :                 sendRequest(
     162             :                     item.tid, item.oid, item.type, item.member, item.arguments,
     163       35631 :                     (item.oid != "UrpProtocolProperties" &&
     164             :                      !item.member.equals(
     165             :                          css::uno::TypeDescription(
     166       66525 :                              "com.sun.star.uno.XInterface::release")) &&
     167        7140 :                      bridge_->isCurrentContextMode()),
     168       11877 :                     item.currentContext);
     169             :             } else {
     170             :                 sendReply(
     171             :                     item.tid, item.member, item.setter, item.exception,
     172      207339 :                     item.returnValue, item.arguments);
     173      207339 :                 if (item.setCurrentContextMode) {
     174           0 :                     bridge_->setCurrentContextMode();
     175             :                 }
     176             :             }
     177      219216 :         }
     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       11980 : 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       11980 :     css::uno::TypeDescription t(type);
     198       11980 :     sal_Int32 functionId = 0;
     199       11980 :     bool forceSynchronous = false;
     200       11980 :     member.makeComplete();
     201       11980 :     switch (member.get()->eTypeClass) {
     202             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     203             :         {
     204             :             typelib_InterfaceAttributeTypeDescription * atd =
     205             :                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
     206         964 :                     member.get());
     207             :             OSL_ASSERT(atd->pInterface != 0);
     208         964 :             if (!t.is()) {
     209         964 :                 t = css::uno::TypeDescription(&atd->pInterface->aBase);
     210             :             }
     211         964 :             t.makeComplete();
     212             :             functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
     213         964 :                 atd->aBase.nPosition];
     214         964 :             if (!inArguments.empty()) { // setter
     215           0 :                 ++functionId;
     216             :             }
     217         964 :             break;
     218             :         }
     219             :     case typelib_TypeClass_INTERFACE_METHOD:
     220             :         {
     221             :             typelib_InterfaceMethodTypeDescription * mtd =
     222             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     223       11016 :                     member.get());
     224             :             assert(mtd->pInterface != 0);
     225       11016 :             if (!t.is()) {
     226        6176 :                 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
     227             :             }
     228       11016 :             t.makeComplete();
     229             :             functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
     230       11016 :                 mtd->aBase.nPosition];
     231       11016 :             forceSynchronous = mtd->bOneWay &&
     232       11016 :                 functionId != SPECIAL_FUNCTION_ID_RELEASE;
     233       11016 :             break;
     234             :         }
     235             :     default:
     236             :         OSL_ASSERT(false); // this cannot happen
     237           0 :         break;
     238             :     }
     239             :     OSL_ASSERT(functionId >= 0);
     240       11980 :     if (functionId > SAL_MAX_UINT16) {
     241           0 :         throw css::uno::RuntimeException("function ID too large for URP");
     242             :     }
     243       11980 :     std::vector< unsigned char > buf;
     244       11980 :     bool newType = !(lastType_.is() && t.equals(lastType_));
     245       11980 :     bool newOid = oid != lastOid_;
     246       11980 :     bool newTid = tid != lastTid_;
     247       11980 :     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        5616 :              (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        5616 :         if (forceSynchronous) {
     258           0 :             Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
     259             :         }
     260        5616 :         if (functionId <= 0xFF) {
     261        5616 :             Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
     262             :         } else {
     263           0 :             Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
     264             :         }
     265        5616 :         if (newType) {
     266        1910 :             marshal_.writeType(&buf, t);
     267             :         }
     268        5616 :         if (newOid) {
     269        2322 :             marshal_.writeOid(&buf, oid);
     270             :         }
     271       11232 :         if (newTid) {
     272        3081 :             marshal_.writeTid(&buf, tid);
     273             :         }
     274        6364 :     } else if (functionId <= 0x3F) { // <= 6 bit function ID
     275        6364 :         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       11980 :     if (currentContextMode) {
     284        7140 :         css::uno::UnoInterfaceReference cc(currentContext);
     285             :         marshal_.writeValue(
     286             :             &buf,
     287             :             css::uno::TypeDescription(
     288             :                 cppu::UnoType<
     289        7140 :                     css::uno::Reference< css::uno::XCurrentContext > >::get()),
     290             :             BinaryAny(
     291             :                 css::uno::TypeDescription(
     292             :                     cppu::UnoType<
     293             :                         css::uno::Reference<
     294        7140 :                             css::uno::XCurrentContext > >::get()),
     295       14280 :                 &cc.m_pUnoI));
     296             :     }
     297       11980 :     switch (member.get()->eTypeClass) {
     298             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     299         964 :         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         964 :         break;
     311             :     case typelib_TypeClass_INTERFACE_METHOD:
     312             :         {
     313             :             typelib_InterfaceMethodTypeDescription * mtd =
     314             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     315       11016 :                     member.get());
     316       11016 :             std::vector< BinaryAny >::const_iterator i(inArguments.begin());
     317       16983 :             for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     318        5967 :                 if (mtd->pParams[j].bIn) {
     319             :                     marshal_.writeValue(
     320             :                         &buf,
     321        5960 :                         css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     322       11920 :                         *i++);
     323             :                 }
     324             :             }
     325             :             OSL_ASSERT(i == inArguments.end());
     326       11016 :             break;
     327             :         }
     328             :     default:
     329             :         OSL_ASSERT(false); // this cannot happen
     330           0 :         break;
     331             :     }
     332       11980 :     sendMessage(buf);
     333       11980 :     lastType_ = t;
     334       11980 :     lastOid_ = oid;
     335       11980 :     lastTid_ = tid;
     336       11980 : }
     337             : 
     338      207434 : 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      207434 :     std::vector< unsigned char > buf;
     346      207434 :     bool newTid = tid != lastTid_;
     347      207434 :     Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
     348             :         // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
     349      207434 :     if (newTid) {
     350        8045 :         marshal_.writeTid(&buf, tid);
     351             :     }
     352      207434 :     if (exception) {
     353             :         marshal_.writeValue(
     354             :             &buf,
     355         937 :             css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
     356         937 :             returnValue);
     357             :     } else {
     358      206497 :         switch (member.get()->eTypeClass) {
     359             :         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     360        3966 :             if (!setter) {
     361             :                 marshal_.writeValue(
     362             :                     &buf,
     363             :                     css::uno::TypeDescription(
     364             :                         reinterpret_cast<
     365             :                             typelib_InterfaceAttributeTypeDescription * >(
     366        3780 :                                 member.get())->
     367             :                         pAttributeTypeRef),
     368        3780 :                     returnValue);
     369             :             }
     370        3966 :             break;
     371             :         case typelib_TypeClass_INTERFACE_METHOD:
     372             :             {
     373             :                 typelib_InterfaceMethodTypeDescription * mtd =
     374             :                     reinterpret_cast<
     375             :                         typelib_InterfaceMethodTypeDescription * >(
     376      202531 :                             member.get());
     377             :                 marshal_.writeValue(
     378             :                     &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
     379      202531 :                     returnValue);
     380             :                 std::vector< BinaryAny >::const_iterator i(
     381      202531 :                     outArguments.begin());
     382      363162 :                 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     383      160631 :                     if (mtd->pParams[j].bOut) {
     384             :                         marshal_.writeValue(
     385             :                             &buf,
     386         101 :                             css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     387         202 :                             *i++);
     388             :                     }
     389             :                 }
     390             :                 OSL_ASSERT(i == outArguments.end());
     391      202531 :                 break;
     392             :             }
     393             :         default:
     394             :             OSL_ASSERT(false); // this cannot happen
     395           0 :             break;
     396             :         }
     397             :     }
     398      207434 :     sendMessage(buf);
     399      207434 :     lastTid_ = tid;
     400      207434 :     bridge_->decrementCalls();
     401      207434 : }
     402             : 
     403      219414 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
     404      219414 :     std::vector< unsigned char > header;
     405      219414 :     if (buffer.size() > SAL_MAX_UINT32) {
     406             :         throw css::uno::RuntimeException(
     407           0 :             "message too large for URP");
     408             :     }
     409      219414 :     Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
     410      219414 :     Marshal::write32(&header, 1);
     411             :     OSL_ASSERT(!buffer.empty());
     412      219414 :     unsigned char const * p = &buffer[0];
     413      219414 :     std::vector< unsigned char >::size_type n = buffer.size();
     414             :     OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
     415      219414 :     sal_Size k = SAL_MAX_INT32 - header.size();
     416      219414 :     if (n < k) {
     417      219414 :         k = static_cast< sal_Size >(n);
     418             :     }
     419             :     css::uno::Sequence< sal_Int8 > s(
     420      438828 :         static_cast< sal_Int32 >(header.size() + k));
     421             :     OSL_ASSERT(!header.empty());
     422             :     memcpy(
     423      219414 :         s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
     424             :     for (;;) {
     425      219414 :         memcpy(s.getArray() + s.getLength() - k, p, k);
     426             :         try {
     427      219414 :             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      219414 :         n = static_cast< std::vector< unsigned char >::size_type >(n - k);
     435      219414 :         if (n == 0) {
     436      219414 :             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      219414 :     }
     445      219414 : }
     446             : 
     447             : }
     448             : 
     449             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11