LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/binaryurp/source - writer.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 161 186 86.6 %
Date: 2013-07-09 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      205891 : Writer::Item::Item() {}
      42             : 
      43       11814 : 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       11814 :     arguments(inArguments), currentContext(theCurrentContext)
      51       11814 : {}
      52             : 
      53      194027 : 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      194027 :     returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
      62      194027 : {}
      63             : 
      64          54 : Writer::Writer(rtl::Reference< Bridge > const  & bridge):
      65             :     Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
      66          54 :     stop_(false)
      67             : {
      68             :     OSL_ASSERT(bridge.is());
      69          54 : }
      70             : 
      71          81 : 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          81 :         css::uno::UnoInterfaceReference());
      81          81 : }
      82             : 
      83          81 : 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          81 :     sendReply(tid, member, false, exception, returnValue,outArguments);
      90          81 : }
      91             : 
      92       11814 : 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       11814 :     css::uno::UnoInterfaceReference cc(current_context::get());
      99       23628 :     osl::MutexGuard g(mutex_);
     100       11814 :     queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
     101       23628 :     items_.set();
     102       11814 : }
     103             : 
     104      194027 : 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      194027 :     osl::MutexGuard g(mutex_);
     111             :     queue_.push_back(
     112             :         Item(
     113             :             tid, member, setter, exception, returnValue, outArguments,
     114      194027 :             setCurrentContextMode));
     115      194027 :     items_.set();
     116      194027 : }
     117             : 
     118          54 : 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          54 :     unblocked_.set();
     123          54 : }
     124             : 
     125          53 : void Writer::stop() {
     126             :     {
     127          53 :         osl::MutexGuard g(mutex_);
     128          53 :         stop_ = true;
     129             :     }
     130          53 :     unblocked_.set();
     131          53 :     items_.set();
     132          53 : }
     133             : 
     134         106 : Writer::~Writer() {}
     135             : 
     136          54 : void Writer::execute() {
     137             :     try {
     138          54 :         unblocked_.wait();
     139             :         for (;;) {
     140      205892 :             items_.wait();
     141      205891 :             Item item;
     142             :             {
     143      205891 :                 osl::MutexGuard g(mutex_);
     144      205891 :                 if (stop_) {
     145         106 :                     return;
     146             :                 }
     147             :                 OSL_ASSERT(!queue_.empty());
     148      205838 :                 item = queue_.front();
     149      205838 :                 queue_.pop_front();
     150      205838 :                 if (queue_.empty()) {
     151      204677 :                     items_.reset();
     152      205838 :                 }
     153             :             }
     154      205838 :             if (item.request) {
     155             :                 sendRequest(
     156             :                     item.tid, item.oid, item.type, item.member, item.arguments,
     157       35436 :                     (item.oid != "UrpProtocolProperties" &&
     158             :                      !item.member.equals(
     159             :                          css::uno::TypeDescription(
     160       66088 :                              "com.sun.star.uno.XInterface::release")) &&
     161        7028 :                      bridge_->isCurrentContextMode()),
     162       11812 :                     item.currentContext);
     163             :             } else {
     164             :                 sendReply(
     165             :                     item.tid, item.member, item.setter, item.exception,
     166      194026 :                     item.returnValue, item.arguments);
     167      194026 :                 if (item.setCurrentContextMode) {
     168           0 :                     bridge_->setCurrentContextMode();
     169             :                 }
     170             :             }
     171      205838 :         }
     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             : }
     181             : 
     182       11893 : void Writer::sendRequest(
     183             :     rtl::ByteSequence const & tid, OUString const & oid,
     184             :     css::uno::TypeDescription const & type,
     185             :     css::uno::TypeDescription const & member,
     186             :     std::vector< BinaryAny > const & inArguments, bool currentContextMode,
     187             :     css::uno::UnoInterfaceReference const & currentContext)
     188             : {
     189             :     OSL_ASSERT(tid.getLength() != 0 && !oid.isEmpty() && member.is());
     190       11893 :     css::uno::TypeDescription t(type);
     191       11893 :     sal_Int32 functionId = 0;
     192       11893 :     bool forceSynchronous = false;
     193       11893 :     member.makeComplete();
     194       11893 :     switch (member.get()->eTypeClass) {
     195             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     196             :         {
     197             :             typelib_InterfaceAttributeTypeDescription * atd =
     198             :                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
     199         902 :                     member.get());
     200             :             OSL_ASSERT(atd->pInterface != 0);
     201         902 :             if (!t.is()) {
     202         902 :                 t = css::uno::TypeDescription(&atd->pInterface->aBase);
     203             :             }
     204         902 :             t.makeComplete();
     205             :             functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
     206         902 :                 atd->aBase.nPosition];
     207         902 :             if (!inArguments.empty()) { // setter
     208           0 :                 ++functionId;
     209             :             }
     210         902 :             break;
     211             :         }
     212             :     case typelib_TypeClass_INTERFACE_METHOD:
     213             :         {
     214             :             typelib_InterfaceMethodTypeDescription * mtd =
     215             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     216       10991 :                     member.get());
     217             :             OSL_ASSERT(mtd->pInterface != 0);
     218       10991 :             if (!t.is()) {
     219        6126 :                 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
     220             :             }
     221       10991 :             t.makeComplete();
     222             :             functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
     223       10991 :                 mtd->aBase.nPosition];
     224       10991 :             forceSynchronous = mtd->bOneWay &&
     225       10991 :                 functionId != SPECIAL_FUNCTION_ID_RELEASE;
     226       10991 :             break;
     227             :         }
     228             :     default:
     229             :         OSL_ASSERT(false); // this cannot happen
     230           0 :         break;
     231             :     }
     232             :     OSL_ASSERT(functionId >= 0);
     233       11893 :     if (functionId > SAL_MAX_UINT16) {
     234             :         throw css::uno::RuntimeException(
     235             :             "function ID too large for URP",
     236           0 :             css::uno::Reference< css::uno::XInterface >());
     237             :     }
     238       11893 :     std::vector< unsigned char > buf;
     239       11893 :     bool newType = !(lastType_.is() && t.equals(lastType_));
     240       11893 :     bool newOid = oid != lastOid_;
     241       11893 :     bool newTid = tid != lastTid_;
     242       11893 :     if (newType || newOid || newTid || forceSynchronous || functionId > 0x3FFF)
     243             :         // > 14 bit function ID
     244             :     {
     245             :         Marshal::write8(
     246             :             &buf,
     247             :             (0xC0 | (newType ? 0x20 : 0) | (newOid ? 0x10 : 0) |
     248             :              (newTid ? 0x08 : 0) | (functionId > 0xFF ? 0x04 : 0) |
     249        5873 :              (forceSynchronous ? 0x01 : 0)));
     250             :             // bit 7: LONGHEADER, bit 6: REQUEST, bit 5: NEWTYPE, bit 4: NEWOID,
     251             :             // bit 3: NEWTID, bit 2: FUNCTIONID16, bit 0: MOREFLAGS
     252        5873 :         if (forceSynchronous) {
     253           0 :             Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
     254             :         }
     255        5873 :         if (functionId <= 0xFF) {
     256        5873 :             Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
     257             :         } else {
     258           0 :             Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
     259             :         }
     260        5873 :         if (newType) {
     261        1799 :             marshal_.writeType(&buf, t);
     262             :         }
     263        5873 :         if (newOid) {
     264        2274 :             marshal_.writeOid(&buf, oid);
     265             :         }
     266       11746 :         if (newTid) {
     267        3476 :             marshal_.writeTid(&buf, tid);
     268             :         }
     269        6020 :     } else if (functionId <= 0x3F) { // <= 6 bit function ID
     270        6020 :         Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
     271             :             // bit 7: !LONGHEADER, bit 6: !FUNCTIONID14
     272             :     } else {
     273             :         Marshal::write8(
     274           0 :             &buf, static_cast< sal_uInt8 >(0x40 | (functionId >> 8)));
     275             :             // bit 7: !LONGHEADER, bit 6: FUNCTIONID14
     276           0 :         Marshal::write8(&buf, functionId & 0xFF);
     277             :     }
     278       11893 :     if (currentContextMode) {
     279        7028 :         css::uno::UnoInterfaceReference cc(currentContext);
     280             :         marshal_.writeValue(
     281             :             &buf,
     282             :             css::uno::TypeDescription(
     283             :                 cppu::UnoType<
     284        7028 :                     css::uno::Reference< css::uno::XCurrentContext > >::get()),
     285             :             BinaryAny(
     286             :                 css::uno::TypeDescription(
     287             :                     cppu::UnoType<
     288             :                         css::uno::Reference<
     289        7028 :                             css::uno::XCurrentContext > >::get()),
     290       14056 :                 &cc.m_pUnoI));
     291             :     }
     292       11893 :     switch (member.get()->eTypeClass) {
     293             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     294         902 :         if (!inArguments.empty()) { // setter
     295             :             OSL_ASSERT(inArguments.size() == 1);
     296             :             marshal_.writeValue(
     297             :                 &buf,
     298             :                 css::uno::TypeDescription(
     299             :                     reinterpret_cast<
     300             :                         typelib_InterfaceAttributeTypeDescription * >(
     301           0 :                             member.get())->
     302             :                     pAttributeTypeRef),
     303           0 :                 inArguments.front());
     304             :         }
     305         902 :         break;
     306             :     case typelib_TypeClass_INTERFACE_METHOD:
     307             :         {
     308             :             typelib_InterfaceMethodTypeDescription * mtd =
     309             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     310       10991 :                     member.get());
     311       10991 :             std::vector< BinaryAny >::const_iterator i(inArguments.begin());
     312       16883 :             for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     313        5892 :                 if (mtd->pParams[j].bIn) {
     314             :                     marshal_.writeValue(
     315             :                         &buf,
     316        5886 :                         css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     317       11772 :                         *i++);
     318             :                 }
     319             :             }
     320             :             OSL_ASSERT(i == inArguments.end());
     321       10991 :             break;
     322             :         }
     323             :     default:
     324             :         OSL_ASSERT(false); // this cannot happen
     325           0 :         break;
     326             :     }
     327       11893 :     sendMessage(buf);
     328       11893 :     lastType_ = t;
     329       11893 :     lastOid_ = oid;
     330       11893 :     lastTid_ = tid;
     331       11893 : }
     332             : 
     333      194107 : void Writer::sendReply(
     334             :     rtl::ByteSequence const & tid,
     335             :     com::sun::star::uno::TypeDescription const & member, bool setter,
     336             :     bool exception, BinaryAny const & returnValue,
     337             :     std::vector< BinaryAny > const & outArguments)
     338             : {
     339             :     OSL_ASSERT(tid.getLength() != 0 && member.is() && member.get()->bComplete);
     340      194107 :     std::vector< unsigned char > buf;
     341      194107 :     bool newTid = tid != lastTid_;
     342      194107 :     Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
     343             :         // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
     344      194107 :     if (newTid) {
     345        3286 :         marshal_.writeTid(&buf, tid);
     346             :     }
     347      194107 :     if (exception) {
     348             :         marshal_.writeValue(
     349             :             &buf,
     350         974 :             css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
     351         974 :             returnValue);
     352             :     } else {
     353      193133 :         switch (member.get()->eTypeClass) {
     354             :         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     355        4010 :             if (!setter) {
     356             :                 marshal_.writeValue(
     357             :                     &buf,
     358             :                     css::uno::TypeDescription(
     359             :                         reinterpret_cast<
     360             :                             typelib_InterfaceAttributeTypeDescription * >(
     361        3792 :                                 member.get())->
     362             :                         pAttributeTypeRef),
     363        3792 :                     returnValue);
     364             :             }
     365        4010 :             break;
     366             :         case typelib_TypeClass_INTERFACE_METHOD:
     367             :             {
     368             :                 typelib_InterfaceMethodTypeDescription * mtd =
     369             :                     reinterpret_cast<
     370             :                         typelib_InterfaceMethodTypeDescription * >(
     371      189123 :                             member.get());
     372             :                 marshal_.writeValue(
     373             :                     &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
     374      189123 :                     returnValue);
     375             :                 std::vector< BinaryAny >::const_iterator i(
     376      189123 :                     outArguments.begin());
     377      347220 :                 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     378      158097 :                     if (mtd->pParams[j].bOut) {
     379             :                         marshal_.writeValue(
     380             :                             &buf,
     381         100 :                             css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     382         200 :                             *i++);
     383             :                     }
     384             :                 }
     385             :                 OSL_ASSERT(i == outArguments.end());
     386      189123 :                 break;
     387             :             }
     388             :         default:
     389             :             OSL_ASSERT(false); // this cannot happen
     390           0 :             break;
     391             :         }
     392             :     }
     393      194107 :     sendMessage(buf);
     394      194107 :     lastTid_ = tid;
     395      194107 :     bridge_->decrementCalls();
     396      194107 : }
     397             : 
     398      206000 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
     399      206000 :     std::vector< unsigned char > header;
     400      206000 :     if (buffer.size() > SAL_MAX_UINT32) {
     401             :         throw css::uno::RuntimeException(
     402             :             "message too large for URP",
     403           0 :             css::uno::Reference< css::uno::XInterface >());
     404             :     }
     405      206000 :     Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
     406      206000 :     Marshal::write32(&header, 1);
     407             :     OSL_ASSERT(!buffer.empty());
     408      206000 :     unsigned char const * p = &buffer[0];
     409      206000 :     std::vector< unsigned char >::size_type n = buffer.size();
     410             :     OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
     411      206000 :     sal_Size k = SAL_MAX_INT32 - header.size();
     412      206000 :     if (n < k) {
     413      206000 :         k = static_cast< sal_Size >(n);
     414             :     }
     415             :     css::uno::Sequence< sal_Int8 > s(
     416      412000 :         static_cast< sal_Int32 >(header.size() + k));
     417             :     OSL_ASSERT(!header.empty());
     418             :     memcpy(
     419      206000 :         s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
     420             :     for (;;) {
     421      206000 :         memcpy(s.getArray() + s.getLength() - k, p, k);
     422             :         try {
     423      206000 :             bridge_->getConnection()->write(s);
     424           0 :         } catch (const css::io::IOException & e) {
     425           0 :             css::uno::Any exc(cppu::getCaughtException());
     426             :             throw css::lang::WrappedTargetRuntimeException(
     427           0 :                 "Binary URP write raised IO exception: " + e.Message,
     428           0 :                 css::uno::Reference< css::uno::XInterface >(), exc);
     429             :         }
     430      206000 :         n = static_cast< std::vector< unsigned char >::size_type >(n - k);
     431      206000 :         if (n == 0) {
     432      206000 :             break;
     433             :         }
     434           0 :         p += k;
     435           0 :         k = SAL_MAX_INT32;
     436           0 :         if (n < k) {
     437           0 :             k = static_cast< sal_Size >(n);
     438             :         }
     439           0 :         s.realloc(k);
     440      206000 :     }
     441      206000 : }
     442             : 
     443             : }
     444             : 
     445             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10