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

Generated by: LCOV version 1.10