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

Generated by: LCOV version 1.10