LCOV - code coverage report
Current view: top level - binaryurp/source - writer.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 168 187 89.8 %
Date: 2014-04-11 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      207494 : Writer::Item::Item() {}
      42             : 
      43       11855 : 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       11855 :     arguments(inArguments), currentContext(theCurrentContext)
      51       11855 : {}
      52             : 
      53      195593 : 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      195593 :     returnValue(theReturnValue), setCurrentContextMode(theSetCurrentContextMode)
      62      195593 : {}
      63             : 
      64          51 : Writer::Writer(rtl::Reference< Bridge > const  & bridge):
      65             :     Thread("binaryurpWriter"), bridge_(bridge), marshal_(bridge, state_),
      66          51 :     stop_(false)
      67             : {
      68             :     OSL_ASSERT(bridge.is());
      69          51 : }
      70             : 
      71          80 : 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          80 :         css::uno::UnoInterfaceReference());
      81          80 : }
      82             : 
      83          73 : 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          73 :     sendReply(tid, member, false, exception, returnValue,outArguments);
      90          73 : }
      91             : 
      92       11855 : 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       11855 :     css::uno::UnoInterfaceReference cc(current_context::get());
      99       23710 :     osl::MutexGuard g(mutex_);
     100       11855 :     queue_.push_back(Item(tid, oid, type, member, inArguments, cc));
     101       23710 :     items_.set();
     102       11855 : }
     103             : 
     104      195593 : 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      195593 :     osl::MutexGuard g(mutex_);
     111             :     queue_.push_back(
     112             :         Item(
     113             :             tid, member, setter, exception, returnValue, outArguments,
     114      195593 :             setCurrentContextMode));
     115      195593 :     items_.set();
     116      195593 : }
     117             : 
     118          51 : 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          51 :     unblocked_.set();
     123          51 : }
     124             : 
     125          50 : void Writer::stop() {
     126             :     {
     127          50 :         osl::MutexGuard g(mutex_);
     128          50 :         stop_ = true;
     129             :     }
     130          50 :     unblocked_.set();
     131          50 :     items_.set();
     132          50 : }
     133             : 
     134         100 : Writer::~Writer() {}
     135             : 
     136          51 : void Writer::execute() {
     137             :     try {
     138          51 :         unblocked_.wait();
     139             :         for (;;) {
     140      207495 :             items_.wait();
     141      207494 :             Item item;
     142             :             {
     143      207494 :                 osl::MutexGuard g(mutex_);
     144      207494 :                 if (stop_) {
     145          98 :                     return;
     146             :                 }
     147             :                 OSL_ASSERT(!queue_.empty());
     148      207446 :                 item = queue_.front();
     149      207446 :                 queue_.pop_front();
     150      207446 :                 if (queue_.empty()) {
     151      205973 :                     items_.reset();
     152      207446 :                 }
     153             :             }
     154      207446 :             if (item.request) {
     155             :                 sendRequest(
     156             :                     item.tid, item.oid, item.type, item.member, item.arguments,
     157       35559 :                     (item.oid != "UrpProtocolProperties" &&
     158             :                      !item.member.equals(
     159             :                          css::uno::TypeDescription(
     160       66331 :                              "com.sun.star.uno.XInterface::release")) &&
     161        7066 :                      bridge_->isCurrentContextMode()),
     162       11853 :                     item.currentContext);
     163             :             } else {
     164             :                 sendReply(
     165             :                     item.tid, item.member, item.setter, item.exception,
     166      195593 :                     item.returnValue, item.arguments);
     167      195591 :                 if (item.setCurrentContextMode) {
     168           0 :                     bridge_->setCurrentContextMode();
     169             :                 }
     170             :             }
     171      207446 :         }
     172           2 :     } 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           2 :     bridge_->terminate(false);
     180           2 :     bridge_.clear();
     181             : }
     182             : 
     183       11933 : 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       11933 :     css::uno::TypeDescription t(type);
     192       11933 :     sal_Int32 functionId = 0;
     193       11933 :     bool forceSynchronous = false;
     194       11933 :     member.makeComplete();
     195       11933 :     switch (member.get()->eTypeClass) {
     196             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     197             :         {
     198             :             typelib_InterfaceAttributeTypeDescription * atd =
     199             :                 reinterpret_cast< typelib_InterfaceAttributeTypeDescription * >(
     200         903 :                     member.get());
     201             :             OSL_ASSERT(atd->pInterface != 0);
     202         903 :             if (!t.is()) {
     203         903 :                 t = css::uno::TypeDescription(&atd->pInterface->aBase);
     204             :             }
     205         903 :             t.makeComplete();
     206             :             functionId = atd->pInterface->pMapMemberIndexToFunctionIndex[
     207         903 :                 atd->aBase.nPosition];
     208         903 :             if (!inArguments.empty()) { // setter
     209           0 :                 ++functionId;
     210             :             }
     211         903 :             break;
     212             :         }
     213             :     case typelib_TypeClass_INTERFACE_METHOD:
     214             :         {
     215             :             typelib_InterfaceMethodTypeDescription * mtd =
     216             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     217       11030 :                     member.get());
     218             :             OSL_ASSERT(mtd->pInterface != 0);
     219       11030 :             if (!t.is()) {
     220        6163 :                 t = css::uno::TypeDescription(&mtd->pInterface->aBase);
     221             :             }
     222       11030 :             t.makeComplete();
     223             :             functionId = mtd->pInterface->pMapMemberIndexToFunctionIndex[
     224       11030 :                 mtd->aBase.nPosition];
     225       11030 :             forceSynchronous = mtd->bOneWay &&
     226       11030 :                 functionId != SPECIAL_FUNCTION_ID_RELEASE;
     227       11030 :             break;
     228             :         }
     229             :     default:
     230             :         OSL_ASSERT(false); // this cannot happen
     231           0 :         break;
     232             :     }
     233             :     OSL_ASSERT(functionId >= 0);
     234       11933 :     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       11933 :     std::vector< unsigned char > buf;
     240       11933 :     bool newType = !(lastType_.is() && t.equals(lastType_));
     241       11933 :     bool newOid = oid != lastOid_;
     242       11933 :     bool newTid = tid != lastTid_;
     243       11933 :     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        5643 :              (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        5643 :         if (forceSynchronous) {
     254           0 :             Marshal::write8(&buf, 0xC0); // bit 7: MUSTREPLY, bit 6: SYNCHRONOUS
     255             :         }
     256        5643 :         if (functionId <= 0xFF) {
     257        5643 :             Marshal::write8(&buf, static_cast< sal_uInt8 >(functionId));
     258             :         } else {
     259           0 :             Marshal::write16(&buf, static_cast< sal_uInt16 >(functionId));
     260             :         }
     261        5643 :         if (newType) {
     262        1796 :             marshal_.writeType(&buf, t);
     263             :         }
     264        5643 :         if (newOid) {
     265        2267 :             marshal_.writeOid(&buf, oid);
     266             :         }
     267       11286 :         if (newTid) {
     268        3228 :             marshal_.writeTid(&buf, tid);
     269             :         }
     270        6290 :     } else if (functionId <= 0x3F) { // <= 6 bit function ID
     271        6290 :         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       11933 :     if (currentContextMode) {
     280        7066 :         css::uno::UnoInterfaceReference cc(currentContext);
     281             :         marshal_.writeValue(
     282             :             &buf,
     283             :             css::uno::TypeDescription(
     284             :                 cppu::UnoType<
     285        7066 :                     css::uno::Reference< css::uno::XCurrentContext > >::get()),
     286             :             BinaryAny(
     287             :                 css::uno::TypeDescription(
     288             :                     cppu::UnoType<
     289             :                         css::uno::Reference<
     290        7066 :                             css::uno::XCurrentContext > >::get()),
     291       14132 :                 &cc.m_pUnoI));
     292             :     }
     293       11933 :     switch (member.get()->eTypeClass) {
     294             :     case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     295         903 :         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         903 :         break;
     307             :     case typelib_TypeClass_INTERFACE_METHOD:
     308             :         {
     309             :             typelib_InterfaceMethodTypeDescription * mtd =
     310             :                 reinterpret_cast< typelib_InterfaceMethodTypeDescription * >(
     311       11030 :                     member.get());
     312       11030 :             std::vector< BinaryAny >::const_iterator i(inArguments.begin());
     313       16961 :             for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     314        5931 :                 if (mtd->pParams[j].bIn) {
     315             :                     marshal_.writeValue(
     316             :                         &buf,
     317        5924 :                         css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     318       11848 :                         *i++);
     319             :                 }
     320             :             }
     321             :             OSL_ASSERT(i == inArguments.end());
     322       11030 :             break;
     323             :         }
     324             :     default:
     325             :         OSL_ASSERT(false); // this cannot happen
     326           0 :         break;
     327             :     }
     328       11933 :     sendMessage(buf);
     329       11933 :     lastType_ = t;
     330       11933 :     lastOid_ = oid;
     331       11933 :     lastTid_ = tid;
     332       11933 : }
     333             : 
     334      195666 : 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      195666 :     std::vector< unsigned char > buf;
     342      195666 :     bool newTid = tid != lastTid_;
     343      195666 :     Marshal::write8(&buf, 0x80 | (exception ? 0x20 : 0) | (newTid ? 0x08 : 0));
     344             :         // bit 7: LONGHEADER; bit 6: !REQUEST; bit 5: EXCEPTION; bit 3: NEWTID
     345      195666 :     if (newTid) {
     346        3080 :         marshal_.writeTid(&buf, tid);
     347             :     }
     348      195666 :     if (exception) {
     349             :         marshal_.writeValue(
     350             :             &buf,
     351         982 :             css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()),
     352         982 :             returnValue);
     353             :     } else {
     354      194684 :         switch (member.get()->eTypeClass) {
     355             :         case typelib_TypeClass_INTERFACE_ATTRIBUTE:
     356        4001 :             if (!setter) {
     357             :                 marshal_.writeValue(
     358             :                     &buf,
     359             :                     css::uno::TypeDescription(
     360             :                         reinterpret_cast<
     361             :                             typelib_InterfaceAttributeTypeDescription * >(
     362        3790 :                                 member.get())->
     363             :                         pAttributeTypeRef),
     364        3790 :                     returnValue);
     365             :             }
     366        4001 :             break;
     367             :         case typelib_TypeClass_INTERFACE_METHOD:
     368             :             {
     369             :                 typelib_InterfaceMethodTypeDescription * mtd =
     370             :                     reinterpret_cast<
     371             :                         typelib_InterfaceMethodTypeDescription * >(
     372      190683 :                             member.get());
     373             :                 marshal_.writeValue(
     374             :                     &buf, css::uno::TypeDescription(mtd->pReturnTypeRef),
     375      190683 :                     returnValue);
     376             :                 std::vector< BinaryAny >::const_iterator i(
     377      190683 :                     outArguments.begin());
     378      349568 :                 for (sal_Int32 j = 0; j != mtd->nParams; ++j) {
     379      158885 :                     if (mtd->pParams[j].bOut) {
     380             :                         marshal_.writeValue(
     381             :                             &buf,
     382         101 :                             css::uno::TypeDescription(mtd->pParams[j].pTypeRef),
     383         202 :                             *i++);
     384             :                     }
     385             :                 }
     386             :                 OSL_ASSERT(i == outArguments.end());
     387      190683 :                 break;
     388             :             }
     389             :         default:
     390             :             OSL_ASSERT(false); // this cannot happen
     391           0 :             break;
     392             :         }
     393             :     }
     394      195666 :     sendMessage(buf);
     395      195664 :     lastTid_ = tid;
     396      195666 :     bridge_->decrementCalls();
     397      195664 : }
     398             : 
     399      207599 : void Writer::sendMessage(std::vector< unsigned char > const & buffer) {
     400      207599 :     std::vector< unsigned char > header;
     401      207599 :     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      207599 :     Marshal::write32(&header, static_cast< sal_uInt32 >(buffer.size()));
     407      207599 :     Marshal::write32(&header, 1);
     408             :     OSL_ASSERT(!buffer.empty());
     409      207599 :     unsigned char const * p = &buffer[0];
     410      207599 :     std::vector< unsigned char >::size_type n = buffer.size();
     411             :     OSL_ASSERT(header.size() <= SAL_MAX_INT32 && SAL_MAX_INT32 <= SAL_MAX_SIZE);
     412      207599 :     sal_Size k = SAL_MAX_INT32 - header.size();
     413      207599 :     if (n < k) {
     414      207599 :         k = static_cast< sal_Size >(n);
     415             :     }
     416             :     css::uno::Sequence< sal_Int8 > s(
     417      415198 :         static_cast< sal_Int32 >(header.size() + k));
     418             :     OSL_ASSERT(!header.empty());
     419             :     memcpy(
     420      207599 :         s.getArray(), &header[0], static_cast< sal_Size >(header.size()));
     421             :     for (;;) {
     422      207599 :         memcpy(s.getArray() + s.getLength() - k, p, k);
     423             :         try {
     424      207601 :             bridge_->getConnection()->write(s);
     425           2 :         } catch (const css::io::IOException & e) {
     426           2 :             css::uno::Any exc(cppu::getCaughtException());
     427             :             throw css::lang::WrappedTargetRuntimeException(
     428           4 :                 "Binary URP write raised IO exception: " + e.Message,
     429           6 :                 css::uno::Reference< css::uno::XInterface >(), exc);
     430             :         }
     431      207597 :         n = static_cast< std::vector< unsigned char >::size_type >(n - k);
     432      207597 :         if (n == 0) {
     433      207597 :             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      207599 :     }
     442      207597 : }
     443             : 
     444             : }
     445             : 
     446             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10