LCOV - code coverage report
Current view: top level - binaryurp/source - bridge.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 407 483 84.3 %
Date: 2015-06-13 12:38:46 Functions: 53 57 93.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 <algorithm>
      23             : #include <cassert>
      24             : #include <cstddef>
      25             : #include <limits>
      26             : #include <memory>
      27             : #include <vector>
      28             : 
      29             : #include "com/sun/star/bridge/InvalidProtocolChangeException.hpp"
      30             : #include "com/sun/star/bridge/XBridge.hpp"
      31             : #include "com/sun/star/bridge/XInstanceProvider.hpp"
      32             : #include "com/sun/star/bridge/XProtocolProperties.hpp"
      33             : #include "com/sun/star/connection/XConnection.hpp"
      34             : #include "com/sun/star/io/IOException.hpp"
      35             : #include "com/sun/star/lang/DisposedException.hpp"
      36             : #include "com/sun/star/lang/EventObject.hpp"
      37             : #include "com/sun/star/lang/XEventListener.hpp"
      38             : #include "com/sun/star/uno/Reference.hxx"
      39             : #include "com/sun/star/uno/RuntimeException.hpp"
      40             : #include "com/sun/star/uno/Sequence.hxx"
      41             : #include "com/sun/star/uno/XInterface.hpp"
      42             : #include "cppuhelper/exc_hlp.hxx"
      43             : #include "cppuhelper/weak.hxx"
      44             : #include "osl/mutex.hxx"
      45             : #include "osl/thread.hxx"
      46             : #include "rtl/byteseq.hxx"
      47             : #include "rtl/random.h"
      48             : #include "rtl/ref.hxx"
      49             : #include "rtl/ustrbuf.hxx"
      50             : #include "rtl/ustring.h"
      51             : #include "rtl/ustring.hxx"
      52             : #include "sal/log.hxx"
      53             : #include "sal/types.h"
      54             : #include "typelib/typeclass.h"
      55             : #include "typelib/typedescription.h"
      56             : #include "typelib/typedescription.hxx"
      57             : #include "uno/dispatcher.hxx"
      58             : #include "uno/environment.hxx"
      59             : #include "uno/lbnames.h"
      60             : 
      61             : #include "binaryany.hxx"
      62             : #include "bridge.hxx"
      63             : #include "bridgefactory.hxx"
      64             : #include "incomingreply.hxx"
      65             : #include "lessoperators.hxx"
      66             : #include "outgoingrequest.hxx"
      67             : #include "outgoingrequests.hxx"
      68             : #include "proxy.hxx"
      69             : #include "reader.hxx"
      70             : 
      71             : namespace binaryurp {
      72             : 
      73             : namespace {
      74             : 
      75          66 : sal_Int32 random() {
      76             :     sal_Int32 n;
      77          66 :     rtlRandomPool pool = rtl_random_createPool();
      78          66 :     rtl_random_getBytes(pool, &n, sizeof n);
      79          66 :     rtl_random_destroyPool(pool);
      80          66 :     return n;
      81             : }
      82             : 
      83           0 : OUString toString(css::uno::TypeDescription const & type) {
      84           0 :     typelib_TypeDescription * d = type.get();
      85             :     assert(d != 0 && d->pTypeName != 0);
      86           0 :     return OUString(d->pTypeName);
      87             : }
      88             : 
      89        1981 : extern "C" void SAL_CALL freeProxyCallback(
      90             :     SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pProxy)
      91             : {
      92             :     assert(pProxy != 0);
      93        1981 :     static_cast< Proxy * >(pProxy)->do_free();
      94        1981 : }
      95             : 
      96         134 : bool isThread(salhelper::Thread * thread) {
      97             :     assert(thread != 0);
      98         134 :     return osl::Thread::getCurrentIdentifier() == thread->getIdentifier();
      99             : }
     100             : 
     101             : class AttachThread {
     102             : public:
     103             :     explicit AttachThread(uno_ThreadPool threadPool);
     104             : 
     105             :     ~AttachThread();
     106             : 
     107       19019 :     rtl::ByteSequence getTid() throw () { return tid_;}
     108             : 
     109             : private:
     110             :     AttachThread(const AttachThread&) SAL_DELETED_FUNCTION;
     111             :     AttachThread& operator=(const AttachThread&) SAL_DELETED_FUNCTION;
     112             : 
     113             :     uno_ThreadPool threadPool_;
     114             :     rtl::ByteSequence tid_;
     115             : };
     116             : 
     117       11879 : AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
     118       11879 :     sal_Sequence * s = 0;
     119       11879 :     uno_getIdOfCurrentThread(&s);
     120       11879 :     tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
     121       11879 :     uno_threadpool_attach(threadPool_);
     122       11879 : }
     123             : 
     124       23758 : AttachThread::~AttachThread() {
     125       11879 :     uno_threadpool_detach(threadPool_);
     126       11879 :     uno_releaseIdFromCurrentThread();
     127       11879 : }
     128             : 
     129             : 
     130             : class PopOutgoingRequest {
     131             : public:
     132             :     PopOutgoingRequest(
     133             :         OutgoingRequests & requests, rtl::ByteSequence const & tid,
     134             :         OutgoingRequest const & request);
     135             : 
     136             :     ~PopOutgoingRequest();
     137             : 
     138             :     void clear();
     139             : 
     140             : private:
     141             :     PopOutgoingRequest(const PopOutgoingRequest&) SAL_DELETED_FUNCTION;
     142             :     PopOutgoingRequest& operator=(const PopOutgoingRequest&) SAL_DELETED_FUNCTION;
     143             : 
     144             :     OutgoingRequests & requests_;
     145             :     rtl::ByteSequence tid_;
     146             :     bool cleared_;
     147             : };
     148             : 
     149        7243 : PopOutgoingRequest::PopOutgoingRequest(
     150             :     OutgoingRequests & requests, rtl::ByteSequence const & tid,
     151             :     OutgoingRequest const & request):
     152        7243 :     requests_(requests), tid_(tid), cleared_(false)
     153             : {
     154        7243 :     requests_.push(tid_, request);
     155        7243 : }
     156             : 
     157       14486 : PopOutgoingRequest::~PopOutgoingRequest() {
     158        7243 :     if (!cleared_) {
     159           0 :         requests_.pop(tid_);
     160             :     }
     161        7243 : }
     162             : 
     163        7243 : void PopOutgoingRequest::clear() {
     164        7243 :     cleared_ = true;
     165        7243 : }
     166             : 
     167             : }
     168             : 
     169      311868 : struct Bridge::SubStub {
     170             :     com::sun::star::uno::UnoInterfaceReference object;
     171             : 
     172             :     sal_uInt32 references;
     173             : };
     174             : 
     175          66 : Bridge::Bridge(
     176             :     rtl::Reference< BridgeFactory > const & factory, OUString const & name,
     177             :     css::uno::Reference< css::connection::XConnection > const & connection,
     178             :     css::uno::Reference< css::bridge::XInstanceProvider > const & provider):
     179             :     factory_(factory), name_(name), connection_(connection),
     180             :     provider_(provider),
     181             :     binaryUno_(UNO_LB_UNO),
     182             :     cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO),
     183             :     binaryToCppMapping_(UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME),
     184             :     protPropTid_(
     185             :         reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"),
     186             :         RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
     187             :     protPropOid_("UrpProtocolProperties"),
     188             :     protPropType_(
     189             :         cppu::UnoType<
     190          66 :             css::uno::Reference< css::bridge::XProtocolProperties > >::get()),
     191             :     protPropRequest_("com.sun.star.bridge.XProtocolProperties::requestChange"),
     192             :     protPropCommit_("com.sun.star.bridge.XProtocolProperties::commitChange"),
     193             :     state_(STATE_INITIAL), threadPool_(0), currentContextMode_(false),
     194             :     proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
     195         132 :     mode_(MODE_REQUESTED)
     196             : {
     197             :     assert(factory.is() && connection.is());
     198          66 :     if (!binaryUno_.is()) {
     199           0 :         throw css::uno::RuntimeException("URP: no binary UNO environment");
     200             :     }
     201          66 :     if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) {
     202           0 :         throw css::uno::RuntimeException("URP: no C++ UNO mapping");
     203             :     }
     204          66 :     passive_.set();
     205          66 : }
     206             : 
     207          66 : void Bridge::start() {
     208          66 :     rtl::Reference< Reader > r(new Reader(this));
     209         132 :     rtl::Reference< Writer > w(new Writer(this));
     210             :     {
     211          66 :         osl::MutexGuard g(mutex_);
     212             :         assert(
     213             :             state_ == STATE_INITIAL && threadPool_ == 0 && !writer_.is() &&
     214             :             !reader_.is());
     215          66 :         threadPool_ = uno_threadpool_create();
     216             :         assert(threadPool_ != 0);
     217          66 :         reader_ = r;
     218          66 :         writer_ = w;
     219          66 :         state_ = STATE_STARTED;
     220             :     }
     221             :     // It is important to call reader_->launch() last here; both
     222             :     // Writer::execute and Reader::execute can call Bridge::terminate, but
     223             :     // Writer::execute is initially blocked in unblocked_.wait() until
     224             :     // Reader::execute has called bridge_->sendRequestChangeRequest(), so
     225             :     // effectively only reader_->launch() can lead to an early call to
     226             :     // Bridge::terminate
     227          66 :     w->launch();
     228         132 :     r->launch();
     229          66 : }
     230             : 
     231         205 : void Bridge::terminate(bool final) {
     232             :     uno_ThreadPool tp;
     233             :     // Make sure function-local variables (Stubs s, etc.) are destroyed before
     234             :     // the final uno_threadpool_destroy/threadPool_ = 0:
     235             :     {
     236         205 :         rtl::Reference< Reader > r;
     237         271 :         rtl::Reference< Writer > w;
     238             :         bool joinW;
     239         271 :         Listeners ls;
     240             :         {
     241         205 :             osl::ClearableMutexGuard g(mutex_);
     242         205 :             switch (state_) {
     243             :             case STATE_INITIAL: // via ~Bridge -> dispose -> terminate
     244             :             case STATE_FINAL:
     245         135 :                 return;
     246             :             case STATE_STARTED:
     247          66 :                 break;
     248             :             case STATE_TERMINATED:
     249           4 :                 if (final) {
     250           3 :                     g.clear();
     251           3 :                     terminated_.wait();
     252             :                     {
     253           3 :                         osl::MutexGuard g2(mutex_);
     254           3 :                         tp = threadPool_;
     255           3 :                         threadPool_ = 0;
     256           3 :                         if (reader_.is()) {
     257           2 :                             if (!isThread(reader_.get())) {
     258           1 :                                 r = reader_;
     259             :                             }
     260           2 :                             reader_.clear();
     261             :                         }
     262           3 :                         if (writer_.is()) {
     263           0 :                             if (!isThread(writer_.get())) {
     264           0 :                                 w = writer_;
     265             :                             }
     266           0 :                             writer_.clear();
     267             :                         }
     268           3 :                         state_ = STATE_FINAL;
     269             :                     }
     270             :                     assert(!(r.is() && w.is()));
     271           3 :                     if (r.is()) {
     272           1 :                         r->join();
     273           2 :                     } else if (w.is()) {
     274           0 :                         w->join();
     275             :                     }
     276           3 :                     if (tp != 0) {
     277           3 :                         uno_threadpool_destroy(tp);
     278             :                     }
     279             :                 }
     280           4 :                 return;
     281             :             }
     282          66 :             tp = threadPool_;
     283             :             assert(!(final && isThread(reader_.get())));
     284          66 :             if (!isThread(reader_.get())) {
     285          64 :                 std::swap(reader_, r);
     286             :             }
     287          66 :             w = writer_;
     288          66 :             joinW = !isThread(writer_.get());
     289             :             assert(!final || joinW);
     290          66 :             if (joinW) {
     291          66 :                 writer_.clear();
     292             :             }
     293          66 :             ls.swap(listeners_);
     294          66 :             state_ = final ? STATE_FINAL : STATE_TERMINATED;
     295             :         }
     296             :         try {
     297          66 :             connection_->close();
     298           0 :         } catch (const css::io::IOException & e) {
     299             :             SAL_INFO("binaryurp", "caught IO exception '" << e.Message << '\'');
     300             :         }
     301             :         assert(w.is());
     302          66 :         w->stop();
     303          66 :         if (r.is()) {
     304          64 :             r->join();
     305             :         }
     306          66 :         if (joinW) {
     307          66 :             w->join();
     308             :         }
     309             :         assert(tp != 0);
     310          66 :         uno_threadpool_dispose(tp);
     311          66 :         Stubs s;
     312             :         {
     313          66 :             osl::MutexGuard g(mutex_);
     314          66 :             s.swap(stubs_);
     315             :         }
     316       17818 :         for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
     317       43145 :             for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j)
     318             :             {
     319             :                 SAL_INFO(
     320             :                     "binaryurp",
     321             :                     "stub '" << i->first << "', '" << toString(j->first)
     322             :                         << "' still mapped at Bridge::terminate");
     323       25393 :                 binaryUno_.get()->pExtEnv->revokeInterface(
     324       25393 :                     binaryUno_.get()->pExtEnv, j->second.object.get());
     325             :             }
     326             :         }
     327          66 :         factory_->removeBridge(this);
     328          67 :         for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
     329             :             try {
     330           1 :                 (*i)->disposing(
     331             :                     css::lang::EventObject(
     332           1 :                         static_cast< cppu::OWeakObject * >(this)));
     333           0 :             } catch (const css::uno::RuntimeException & e) {
     334             :                 SAL_WARN(
     335             :                     "binaryurp",
     336             :                     "caught runtime exception '" << e.Message << '\'');
     337             :             }
     338         132 :         }
     339             :     }
     340          66 :     if (final) {
     341          63 :         uno_threadpool_destroy(tp);
     342             :     }
     343             :     {
     344          66 :         osl::MutexGuard g(mutex_);
     345          66 :         if (final) {
     346          63 :             threadPool_ = 0;
     347          66 :         }
     348             :     }
     349          66 :     terminated_.set();
     350             : }
     351             : 
     352             : 
     353             : 
     354             : 
     355          67 : BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
     356          67 :     css::uno::Any in(cppAny);
     357          67 :     BinaryAny out;
     358          67 :     out.~BinaryAny();
     359             :     uno_copyAndConvertData(
     360          67 :         &out.get(), &in,
     361          67 :         css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
     362         201 :         cppToBinaryMapping_.get());
     363          67 :     return out;
     364             : }
     365             : 
     366      278654 : uno_ThreadPool Bridge::getThreadPool() {
     367      278654 :     osl::MutexGuard g(mutex_);
     368      278654 :     checkDisposed();
     369             :     assert(threadPool_ != 0);
     370      278626 :     return threadPool_;
     371             : }
     372             : 
     373      219484 : rtl::Reference< Writer > Bridge::getWriter() {
     374      219484 :     osl::MutexGuard g(mutex_);
     375      219484 :     checkDisposed();
     376             :     assert(writer_.is());
     377      219482 :     return writer_;
     378             : }
     379             : 
     380      218931 : css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
     381             :     OUString const & oid, css::uno::TypeDescription const & type)
     382             : {
     383             :     assert(type.is());
     384      218931 :     if (oid.isEmpty()) {
     385      208378 :         return css::uno::UnoInterfaceReference();
     386             :     }
     387       10553 :     css::uno::UnoInterfaceReference obj(findStub(oid, type));
     388       10553 :     if (!obj.is()) {
     389        4773 :         binaryUno_.get()->pExtEnv->getRegisteredInterface(
     390        4773 :             binaryUno_.get()->pExtEnv,
     391             :             reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
     392        9546 :             reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
     393        4773 :         if (obj.is()) {
     394        2784 :             makeReleaseCall(oid, type);
     395             :         } else {
     396        1989 :             obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
     397             :             {
     398        1989 :                 osl::MutexGuard g(mutex_);
     399             :                 assert(proxies_ < std::numeric_limits< std::size_t >::max());
     400        1989 :                 ++proxies_;
     401             :             }
     402        1989 :             binaryUno_.get()->pExtEnv->registerProxyInterface(
     403        1989 :                 binaryUno_.get()->pExtEnv,
     404             :                 reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
     405             :                 oid.pData,
     406             :                 reinterpret_cast< typelib_InterfaceTypeDescription * >(
     407        3978 :                     type.get()));
     408             :         }
     409             :     }
     410       10553 :     return obj;
     411             : }
     412             : 
     413       86424 : OUString Bridge::registerOutgoingInterface(
     414             :     css::uno::UnoInterfaceReference const & object,
     415             :     css::uno::TypeDescription const & type)
     416             : {
     417             :     assert(type.is());
     418       86424 :     if (!object.is()) {
     419        8508 :         return OUString();
     420             :     }
     421       77916 :     OUString oid;
     422       77916 :     if (!Proxy::isProxy(this, object, &oid)) {
     423       77785 :         binaryUno_.get()->pExtEnv->getObjectIdentifier(
     424       77785 :             binaryUno_.get()->pExtEnv, &oid.pData, object.get());
     425       77785 :         osl::MutexGuard g(mutex_);
     426       77785 :         Stubs::iterator i(stubs_.find(oid));
     427      155570 :         Stub newStub;
     428       77785 :         Stub * stub = i == stubs_.end() ? &newStub : &i->second;
     429       77785 :         Stub::iterator j(stub->find(type));
     430             :         //TODO: Release sub-stub if it is not successfully sent to remote side
     431             :         // (otherwise, stub will leak until terminate()):
     432       77785 :         if (j == stub->end()) {
     433       51978 :             j = stub->insert(Stub::value_type(type, SubStub())).first;
     434       51978 :             if (stub == &newStub) {
     435       32700 :                 i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
     436       32700 :                 std::swap(i->second, newStub);
     437       32700 :                 j = i->second.find(type);
     438             :                 assert(j !=  i->second.end());
     439             :             }
     440       51978 :             j->second.object = object;
     441       51978 :             j->second.references = 1;
     442       51978 :             binaryUno_.get()->pExtEnv->registerInterface(
     443       51978 :                 binaryUno_.get()->pExtEnv,
     444       51978 :                 reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
     445             :                 oid.pData,
     446             :                 reinterpret_cast< typelib_InterfaceTypeDescription * >(
     447      155934 :                     type.get()));
     448             :         } else {
     449             :             assert(stub != &newStub);
     450       25807 :             if (j->second.references == SAL_MAX_UINT32) {
     451             :                 throw css::uno::RuntimeException(
     452           0 :                     "URP: stub reference count overflow");
     453             :             }
     454       25807 :             ++j->second.references;
     455       77785 :         }
     456             :     }
     457       77916 :     return oid;
     458             : }
     459             : 
     460      217894 : css::uno::UnoInterfaceReference Bridge::findStub(
     461             :     OUString const & oid, css::uno::TypeDescription const & type)
     462             : {
     463             :     assert(!oid.isEmpty() && type.is());
     464      217894 :     osl::MutexGuard g(mutex_);
     465      217894 :     Stubs::iterator i(stubs_.find(oid));
     466      217894 :     if (i != stubs_.end()) {
     467      213025 :         Stub::iterator j(i->second.find(type));
     468      213025 :         if (j != i->second.end()) {
     469      423347 :             return j->second.object;
     470             :         }
     471        2726 :         for (j = i->second.begin(); j != i->second.end(); ++j) {
     472        2726 :             if (typelib_typedescription_isAssignableFrom(
     473        2726 :                     type.get(), j->first.get()))
     474             :             {
     475        2703 :                 return j->second.object;
     476             :             }
     477             :         }
     478             :     }
     479        4869 :     return css::uno::UnoInterfaceReference();
     480             : }
     481             : 
     482       52266 : void Bridge::releaseStub(
     483             :     OUString const & oid, css::uno::TypeDescription const & type)
     484             : {
     485             :     assert(!oid.isEmpty() && type.is());
     486       52266 :     css::uno::UnoInterfaceReference obj;
     487             :     bool unused;
     488             :     {
     489       52266 :         osl::MutexGuard g(mutex_);
     490       52266 :         Stubs::iterator i(stubs_.find(oid));
     491       52266 :         if (i == stubs_.end()) {
     492          30 :             throw css::uno::RuntimeException("URP: release unknown stub");
     493             :         }
     494       52236 :         Stub::iterator j(i->second.find(type));
     495       52236 :         if (j == i->second.end()) {
     496           0 :             throw css::uno::RuntimeException("URP: release unknown stub");
     497             :         }
     498             :         assert(j->second.references > 0);
     499       52236 :         --j->second.references;
     500       52236 :         if (j->second.references == 0) {
     501       26585 :             obj = j->second.object;
     502       26585 :             i->second.erase(j);
     503       26585 :             if (i->second.empty()) {
     504       14948 :                 stubs_.erase(i);
     505             :             }
     506             :         }
     507       52266 :         unused = becameUnused();
     508             :     }
     509       52236 :     if (obj.is()) {
     510       26585 :         binaryUno_.get()->pExtEnv->revokeInterface(
     511       26585 :             binaryUno_.get()->pExtEnv, obj.get());
     512             :     }
     513       52266 :     terminateWhenUnused(unused);
     514       52236 : }
     515             : 
     516           0 : void Bridge::resurrectProxy(Proxy & proxy) {
     517           0 :     uno_Interface * p = &proxy;
     518           0 :     binaryUno_.get()->pExtEnv->registerProxyInterface(
     519           0 :         binaryUno_.get()->pExtEnv,
     520             :         reinterpret_cast< void ** >(&p), &freeProxyCallback,
     521             :         proxy.getOid().pData,
     522             :         reinterpret_cast< typelib_InterfaceTypeDescription * >(
     523           0 :             proxy.getType().get()));
     524             :     assert(p == &proxy);
     525           0 : }
     526             : 
     527        1981 : void Bridge::revokeProxy(Proxy & proxy) {
     528        1981 :     binaryUno_.get()->pExtEnv->revokeInterface(
     529        1981 :         binaryUno_.get()->pExtEnv, &proxy);
     530        1981 : }
     531             : 
     532        1981 : void Bridge::freeProxy(Proxy & proxy) {
     533             :     try {
     534        2007 :         makeReleaseCall(proxy.getOid(), proxy.getType());
     535          26 :     } catch (const css::uno::RuntimeException & e) {
     536             :         SAL_INFO(
     537             :             "binaryurp", "caught runtime exception '" << e.Message << '\'');
     538           0 :     } catch (const std::exception & e) {
     539             :         SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
     540             :     }
     541             :     bool unused;
     542             :     {
     543        1981 :         osl::MutexGuard g(mutex_);
     544             :         assert(proxies_ > 0);
     545        1981 :         --proxies_;
     546        1981 :         unused = becameUnused();
     547             :     }
     548        1981 :     terminateWhenUnused(unused);
     549        1981 : }
     550             : 
     551      266945 : void Bridge::incrementCalls(bool normalCall) throw () {
     552      266945 :     osl::MutexGuard g(mutex_);
     553             :     assert(calls_ < std::numeric_limits< std::size_t >::max());
     554      266945 :     ++calls_;
     555      266945 :     normalCall_ |= normalCall;
     556      266945 : }
     557             : 
     558      266943 : void Bridge::decrementCalls() {
     559             :     bool unused;
     560             :     {
     561      266943 :         osl::MutexGuard g(mutex_);
     562             :         assert(calls_ > 0);
     563      266943 :         --calls_;
     564      266943 :         unused = becameUnused();
     565             :     }
     566      266943 :     terminateWhenUnused(unused);
     567      266943 : }
     568             : 
     569      214481 : void Bridge::incrementActiveCalls() throw () {
     570      214481 :     osl::MutexGuard g(mutex_);
     571             :     assert(
     572             :         activeCalls_ <= calls_ &&
     573             :         activeCalls_ < std::numeric_limits< std::size_t >::max());
     574      214481 :     ++activeCalls_;
     575      214481 :     passive_.reset();
     576      214481 : }
     577             : 
     578      214481 : void Bridge::decrementActiveCalls() throw () {
     579      214481 :     osl::MutexGuard g(mutex_);
     580             :     assert(activeCalls_ <= calls_ && activeCalls_ > 0);
     581      214481 :     --activeCalls_;
     582      214481 :     if (activeCalls_ == 0) {
     583      198333 :         passive_.set();
     584      214481 :     }
     585      214481 : }
     586             : 
     587        7142 : bool Bridge::makeCall(
     588             :     OUString const & oid, css::uno::TypeDescription const & member,
     589             :     bool setter, std::vector< BinaryAny > const & inArguments,
     590             :     BinaryAny * returnValue, std::vector< BinaryAny > * outArguments)
     591             : {
     592        7142 :     std::unique_ptr< IncomingReply > resp;
     593             :     {
     594        7142 :         uno_ThreadPool tp = getThreadPool();
     595        7140 :         AttachThread att(tp);
     596             :         PopOutgoingRequest pop(
     597             :             outgoingRequests_, att.getTid(),
     598       14280 :             OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
     599             :         sendRequest(
     600             :             att.getTid(), oid, css::uno::TypeDescription(), member,
     601        7140 :             inArguments);
     602        7140 :         pop.clear();
     603        7140 :         incrementCalls(true);
     604        7140 :         incrementActiveCalls();
     605             :         void * job;
     606        7140 :         uno_threadpool_enter(tp, &job);
     607        7140 :         resp.reset(static_cast< IncomingReply * >(job));
     608        7140 :         decrementActiveCalls();
     609       14280 :         decrementCalls();
     610             :     }
     611        7140 :     if (resp.get() == 0) {
     612             :         throw css::lang::DisposedException(
     613             :             "Binary URP bridge disposed during call",
     614           0 :             static_cast< cppu::OWeakObject * >(this));
     615             :     }
     616        7140 :     *returnValue = resp->returnValue;
     617        7140 :     if (!resp->exception) {
     618        7124 :         *outArguments = resp->outArguments;
     619             :     }
     620        7142 :     return resp->exception;
     621             : }
     622             : 
     623          66 : void Bridge::sendRequestChangeRequest() {
     624             :     assert(mode_ == MODE_REQUESTED);
     625          66 :     random_ = random();
     626          66 :     std::vector< BinaryAny > a;
     627             :     a.push_back(
     628             :         BinaryAny(
     629          66 :             css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
     630         132 :             &random_));
     631          66 :     sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
     632          66 : }
     633             : 
     634          66 : void Bridge::handleRequestChangeReply(
     635             :     bool exception, BinaryAny const & returnValue)
     636             : {
     637             :     try {
     638          66 :         throwException(exception, returnValue);
     639           0 :     } catch (css::uno::RuntimeException & e) {
     640             :         // Before OOo 2.2, Java URP would throw a RuntimeException when
     641             :         // receiving a requestChange message (see i#35277 "Java URP: Support
     642             :         // Manipulation of Protocol Properties"):
     643           0 :         if (mode_ != MODE_REQUESTED) {
     644           0 :             throw;
     645             :         }
     646             :         SAL_WARN(
     647             :             "binaryurp",
     648             :             "requestChange caught RuntimeException \'" << e.Message
     649             :                 << "' in state 'requested'");
     650           0 :         mode_ = MODE_NORMAL;
     651           0 :         getWriter()->unblock();
     652           0 :         decrementCalls();
     653          66 :         return;
     654             :     }
     655             :     sal_Int32 n = *static_cast< sal_Int32 * >(
     656             :         returnValue.getValue(
     657          66 :             css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
     658          66 :     sal_Int32 exp = 0;
     659          66 :     switch (mode_) {
     660             :     case MODE_REQUESTED:
     661             :     case MODE_REPLY_1:
     662          37 :         exp = 1;
     663          37 :         break;
     664             :     case MODE_REPLY_MINUS1:
     665           0 :         exp = -1;
     666           0 :         mode_ = MODE_REQUESTED;
     667           0 :         break;
     668             :     case MODE_REPLY_0:
     669          29 :         exp = 0;
     670          29 :         mode_ = MODE_WAIT;
     671          29 :         break;
     672             :     default:
     673             :         assert(false); // this cannot happen
     674           0 :         break;
     675             :     }
     676          66 :     if (n != exp) {
     677             :         throw css::uno::RuntimeException(
     678             :             "URP: requestChange reply with unexpected return value received",
     679           0 :             static_cast< cppu::OWeakObject * >(this));
     680             :     }
     681          66 :     decrementCalls();
     682          66 :     switch (exp) {
     683             :     case -1:
     684           0 :         sendRequestChangeRequest();
     685           0 :         break;
     686             :     case 0:
     687          29 :         break;
     688             :     case 1:
     689          37 :         sendCommitChangeRequest();
     690          37 :         break;
     691             :     default:
     692             :         assert(false); // this cannot happen
     693           0 :         break;
     694             :     }
     695             : }
     696             : 
     697          37 : void Bridge::handleCommitChangeReply(
     698             :     bool exception, BinaryAny const & returnValue)
     699             : {
     700          37 :     bool ccMode = true;
     701             :     try {
     702          37 :         throwException(exception, returnValue);
     703           0 :     } catch (const css::bridge::InvalidProtocolChangeException &) {
     704           0 :         ccMode = false;
     705             :     }
     706          37 :     if (ccMode) {
     707          37 :         setCurrentContextMode();
     708             :     }
     709             :     assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
     710          37 :     mode_ = MODE_NORMAL;
     711          37 :     getWriter()->unblock();
     712          37 :     decrementCalls();
     713          37 : }
     714             : 
     715          66 : void Bridge::handleRequestChangeRequest(
     716             :     rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
     717             : {
     718             :     assert(inArguments.size() == 1);
     719          66 :     switch (mode_) {
     720             :     case MODE_REQUESTED:
     721             :         {
     722             :             sal_Int32 n2 = *static_cast< sal_Int32 * >(
     723          66 :                 inArguments[0].getValue(
     724             :                     css::uno::TypeDescription(
     725         132 :                         cppu::UnoType< sal_Int32 >::get())));
     726             :             sal_Int32 ret;
     727          66 :             if (n2 > random_) {
     728          29 :                 ret = 1;
     729          29 :                 mode_ = MODE_REPLY_0;
     730          37 :             } else if (n2 == random_) {
     731           0 :                 ret = -1;
     732           0 :                 mode_ = MODE_REPLY_MINUS1;
     733             :             } else {
     734          37 :                 ret = 0;
     735          37 :                 mode_ = MODE_REPLY_1;
     736             :             }
     737             :             getWriter()->sendDirectReply(
     738             :                 tid, protPropRequest_, false,
     739             :                 BinaryAny(
     740             :                     css::uno::TypeDescription(
     741          66 :                         cppu::UnoType< sal_Int32 >::get()),
     742             :                     &ret),
     743         132 :             std::vector< BinaryAny >());
     744          66 :             break;
     745             :         }
     746             :     case MODE_NORMAL:
     747             :         {
     748           0 :             mode_ = MODE_NORMAL_WAIT;
     749           0 :             sal_Int32 ret = 1;
     750             :             getWriter()->queueReply(
     751             :                 tid, protPropRequest_, false, false,
     752             :                 BinaryAny(
     753             :                     css::uno::TypeDescription(
     754           0 :                         cppu::UnoType< sal_Int32 >::get()),
     755             :                     &ret),
     756           0 :             std::vector< BinaryAny >(), false);
     757           0 :             break;
     758             :         }
     759             :     default:
     760             :         throw css::uno::RuntimeException(
     761             :             "URP: unexpected requestChange request received",
     762           0 :             static_cast< cppu::OWeakObject * >(this));
     763             :     }
     764          66 : }
     765             : 
     766          29 : void Bridge::handleCommitChangeRequest(
     767             :     rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
     768             : {
     769          29 :     bool ccMode = false;
     770          29 :     bool exc = false;
     771          29 :     BinaryAny ret;
     772             :     assert(inArguments.size() == 1);
     773          58 :     css::uno::Sequence< css::bridge::ProtocolProperty > s;
     774          29 :     bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
     775             :     assert(ok);
     776             :     (void) ok; // avoid warnings
     777          58 :     for (sal_Int32 i = 0; i != s.getLength(); ++i) {
     778          29 :         if (s[i].Name == "CurrentContext") {
     779          29 :             ccMode = true;
     780             :         } else {
     781           0 :             ccMode = false;
     782           0 :             exc = true;
     783           0 :             ret = mapCppToBinaryAny(
     784             :                 css::uno::makeAny(
     785             :                     css::bridge::InvalidProtocolChangeException(
     786             :                         "InvalidProtocolChangeException",
     787           0 :                         css::uno::Reference< css::uno::XInterface >(), s[i],
     788           0 :                         1)));
     789           0 :             break;
     790             :         }
     791             :     }
     792          29 :     switch (mode_) {
     793             :     case MODE_WAIT:
     794             :         getWriter()->sendDirectReply(
     795          29 :             tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
     796          29 :         if (ccMode) {
     797          29 :             setCurrentContextMode();
     798          29 :             mode_ = MODE_NORMAL;
     799          29 :             getWriter()->unblock();
     800             :         } else {
     801           0 :             mode_ = MODE_REQUESTED;
     802           0 :             sendRequestChangeRequest();
     803             :         }
     804          29 :         break;
     805             :     case MODE_NORMAL_WAIT:
     806             :         getWriter()->queueReply(
     807             :             tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(),
     808           0 :             ccMode);
     809           0 :         mode_ = MODE_NORMAL;
     810           0 :         break;
     811             :     default:
     812             :         throw css::uno::RuntimeException(
     813             :             "URP: unexpected commitChange request received",
     814           0 :             static_cast< cppu::OWeakObject * >(this));
     815          29 :     }
     816          29 : }
     817             : 
     818        7243 : OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
     819        7243 :     OutgoingRequest req(outgoingRequests_.top(tid));
     820        7243 :     outgoingRequests_.pop(tid);
     821        7243 :     return req;
     822             : }
     823             : 
     824      259702 : bool Bridge::isProtocolPropertiesRequest(
     825             :     OUString const & oid, css::uno::TypeDescription const & type) const
     826             : {
     827      259702 :     return oid == protPropOid_ && type.equals(protPropType_);
     828             : }
     829             : 
     830          66 : void Bridge::setCurrentContextMode() {
     831          66 :     osl::MutexGuard g(mutex_);
     832          66 :     currentContextMode_ = true;
     833          66 : }
     834             : 
     835      214481 : bool Bridge::isCurrentContextMode() {
     836      214481 :     osl::MutexGuard g(mutex_);
     837      214481 :     return currentContextMode_;
     838             : }
     839             : 
     840         189 : Bridge::~Bridge() {
     841             : #if OSL_DEBUG_LEVEL > 0
     842             :     {
     843             :         osl::MutexGuard g(mutex_);
     844             :         SAL_WARN_IF(
     845             :             state_ == STATE_STARTED || state_ == STATE_TERMINATED, "binaryurp",
     846             :             "undisposed bridge, potential deadlock ahead");
     847             :     }
     848             : #endif
     849          63 :     dispose();
     850         126 : }
     851             : 
     852           2 : css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
     853             :     OUString const & sInstanceName) throw (css::uno::RuntimeException, std::exception)
     854             : {
     855           2 :     if (sInstanceName.isEmpty()) {
     856             :         throw css::uno::RuntimeException(
     857             :             "XBridge::getInstance sInstanceName must be non-empty",
     858           0 :             static_cast< cppu::OWeakObject * >(this));
     859             :     }
     860          49 :     for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
     861          47 :         if (sInstanceName[i] > 0x7F) {
     862             :             throw css::uno::RuntimeException(
     863             :                 "XBridge::getInstance sInstanceName contains non-ASCII"
     864           0 :                 " character");
     865             :         }
     866             :     }
     867           2 :     css::uno::TypeDescription ifc(cppu::UnoType<css::uno::XInterface>::get());
     868           2 :     typelib_TypeDescription * p = ifc.get();
     869           4 :     std::vector< BinaryAny > inArgs;
     870             :     inArgs.push_back(
     871             :         BinaryAny(
     872           2 :             css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
     873           2 :             &p));
     874           4 :     BinaryAny ret;
     875           4 :     std::vector< BinaryAny> outArgs;
     876             :     bool exc = makeCall(
     877             :         sInstanceName,
     878             :         css::uno::TypeDescription(
     879             :             "com.sun.star.uno.XInterface::queryInterface"),
     880           2 :         false, inArgs, &ret, &outArgs);
     881           2 :     throwException(exc, ret);
     882             :     return css::uno::Reference< css::uno::XInterface >(
     883             :         static_cast< css::uno::XInterface * >(
     884             :             binaryToCppMapping_.mapInterface(
     885           2 :                 *static_cast< uno_Interface ** >(ret.getValue(ifc)),
     886           4 :                 ifc.get())),
     887           4 :         css::uno::UNO_REF_NO_ACQUIRE);
     888             : }
     889             : 
     890          66 : OUString Bridge::getName() throw (css::uno::RuntimeException, std::exception) {
     891          66 :     return name_;
     892             : }
     893             : 
     894           0 : OUString Bridge::getDescription() throw (css::uno::RuntimeException, std::exception) {
     895           0 :     OUStringBuffer b(name_);
     896           0 :     b.append(':');
     897           0 :     b.append(connection_->getDescription());
     898           0 :     return b.makeStringAndClear();
     899             : }
     900             : 
     901         127 : void Bridge::dispose() throw (css::uno::RuntimeException, std::exception) {
     902             :     // For terminate(true) not to deadlock, an external protocol must ensure
     903             :     // that dispose is not called from a thread pool worker thread (that dispose
     904             :     // is never called from the reader or writer thread is already ensured
     905             :     // internally):
     906         127 :     terminate(true);
     907             :     // OOo expects dispose to not return while there are still remote calls in
     908             :     // progress; an external protocol must ensure that dispose is not called
     909             :     // from within an incoming or outgoing remote call, as passive_.wait() would
     910             :     // otherwise deadlock:
     911         127 :     passive_.wait();
     912         127 : }
     913             : 
     914           1 : void Bridge::addEventListener(
     915             :     css::uno::Reference< css::lang::XEventListener > const & xListener)
     916             :     throw (css::uno::RuntimeException, std::exception)
     917             : {
     918             :     assert(xListener.is());
     919             :     {
     920           1 :         osl::MutexGuard g(mutex_);
     921             :         assert(state_ != STATE_INITIAL);
     922           1 :         if (state_ == STATE_STARTED) {
     923           1 :             listeners_.push_back(xListener);
     924           2 :             return;
     925           0 :         }
     926             :     }
     927           0 :     xListener->disposing(
     928           0 :         css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
     929             : }
     930             : 
     931           0 : void Bridge::removeEventListener(
     932             :     css::uno::Reference< css::lang::XEventListener > const & aListener)
     933             :     throw (css::uno::RuntimeException, std::exception)
     934             : {
     935           0 :     osl::MutexGuard g(mutex_);
     936             :     Listeners::iterator i(
     937           0 :         std::find(listeners_.begin(), listeners_.end(), aListener));
     938           0 :     if (i != listeners_.end()) {
     939           0 :         listeners_.erase(i);
     940           0 :     }
     941           0 : }
     942             : 
     943          37 : void Bridge::sendCommitChangeRequest() {
     944             :     assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
     945          37 :     css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
     946          37 :     s[0].Name = "CurrentContext";
     947          74 :     std::vector< BinaryAny > a;
     948          37 :     a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
     949          74 :     sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
     950          37 : }
     951             : 
     952         103 : void Bridge::sendProtPropRequest(
     953             :     OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments)
     954             : {
     955             :     assert(
     956             :         kind == OutgoingRequest::KIND_REQUEST_CHANGE ||
     957             :         kind == OutgoingRequest::KIND_COMMIT_CHANGE);
     958         103 :     incrementCalls(false);
     959             :     css::uno::TypeDescription member(
     960             :         kind == OutgoingRequest::KIND_REQUEST_CHANGE
     961         103 :         ? protPropRequest_ : protPropCommit_);
     962             :     PopOutgoingRequest pop(
     963         206 :         outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
     964             :     getWriter()->sendDirectRequest(
     965         103 :         protPropTid_, protPropOid_, protPropType_, member, inArguments);
     966         206 :     pop.clear();
     967         103 : }
     968             : 
     969        4765 : void Bridge::makeReleaseCall(
     970             :     OUString const & oid, css::uno::TypeDescription const & type)
     971             : {
     972        4765 :     AttachThread att(getThreadPool());
     973             :     sendRequest(
     974             :         att.getTid(), oid, type,
     975             :         css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
     976        4739 :         std::vector< BinaryAny >());
     977        4739 : }
     978             : 
     979       11879 : void Bridge::sendRequest(
     980             :     rtl::ByteSequence const & tid, OUString const & oid,
     981             :     css::uno::TypeDescription const & type,
     982             :     css::uno::TypeDescription const & member,
     983             :     std::vector< BinaryAny > const & inArguments)
     984             : {
     985       11879 :     getWriter()->queueRequest(tid, oid, type, member, inArguments);
     986       11879 : }
     987             : 
     988         105 : void Bridge::throwException(bool exception, BinaryAny const & value) {
     989         105 :     if (exception) {
     990           0 :         cppu::throwException(mapBinaryToCppAny(value));
     991             :     }
     992         105 : }
     993             : 
     994          29 : css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
     995          29 :     BinaryAny in(binaryAny);
     996          29 :     css::uno::Any out;
     997          29 :     out.~Any();
     998             :     uno_copyAndConvertData(
     999          29 :         &out, &in.get(),
    1000          29 :         css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
    1001          87 :         binaryToCppMapping_.get());
    1002          29 :     return out;
    1003             : }
    1004             : 
    1005      321160 : bool Bridge::becameUnused() const {
    1006      321160 :     return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
    1007             : }
    1008             : 
    1009      321160 : void Bridge::terminateWhenUnused(bool unused) {
    1010      321160 :     if (unused) {
    1011             :         // That the current thread considers the bridge unused implies that it
    1012             :         // is not within an incoming or outgoing remote call (so calling
    1013             :         // terminate cannot lead to deadlock):
    1014          10 :         terminate(false);
    1015             :     }
    1016      321160 : }
    1017             : 
    1018      498138 : void Bridge::checkDisposed() {
    1019             :     assert(state_ != STATE_INITIAL);
    1020      498138 :     if (state_ != STATE_STARTED) {
    1021             :         throw css::lang::DisposedException(
    1022             :             "Binary URP bridge already disposed",
    1023          30 :             static_cast< cppu::OWeakObject * >(this));
    1024             :     }
    1025      498108 : }
    1026             : 
    1027             : }
    1028             : 
    1029             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11