LCOV - code coverage report
Current view: top level - libreoffice/binaryurp/source - bridge.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 479 0.0 %
Date: 2012-12-27 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 <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           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             :         RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
     185             :     protPropOid_(RTL_CONSTASCII_USTRINGPARAM("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             :                 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             :                         assert(!(reader_.is() && isThread(reader_.get())));
     259           0 :                         std::swap(reader_, r);
     260             :                         assert(!(writer_.is() && isThread(writer_.get())));
     261           0 :                         std::swap(writer_, w);
     262           0 :                         state_ = STATE_FINAL;
     263             :                     }
     264             :                     assert(!(r.is() && w.is()));
     265           0 :                     if (r.is()) {
     266           0 :                         r->join();
     267           0 :                     } else if (w.is()) {
     268           0 :                         w->join();
     269             :                     }
     270           0 :                     if (tp != 0) {
     271           0 :                         uno_threadpool_destroy(tp);
     272             :                     }
     273             :                 }
     274             :                 return;
     275             :             }
     276           0 :             tp = threadPool_;
     277             :             assert(!(final && isThread(reader_.get())));
     278           0 :             if (!isThread(reader_.get())) {
     279           0 :                 std::swap(reader_, r);
     280             :             }
     281           0 :             w = writer_;
     282           0 :             joinW = !isThread(writer_.get());
     283             :             assert(!final || joinW);
     284           0 :             if (joinW) {
     285           0 :                 writer_.clear();
     286             :             }
     287           0 :             ls.swap(listeners_);
     288           0 :             state_ = final ? STATE_FINAL : STATE_TERMINATED;
     289             :         }
     290             :         try {
     291           0 :             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           0 :         w->stop();
     297           0 :         if (r.is()) {
     298           0 :             r->join();
     299             :         }
     300           0 :         if (joinW) {
     301           0 :             w->join();
     302             :         }
     303             :         assert(tp != 0);
     304           0 :         uno_threadpool_dispose(tp);
     305           0 :         Stubs s;
     306             :         {
     307           0 :             osl::MutexGuard g(mutex_);
     308           0 :             s.swap(stubs_);
     309             :         }
     310           0 :         for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
     311           0 :             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           0 :                 binaryUno_.get()->pExtEnv->revokeInterface(
     318           0 :                     binaryUno_.get()->pExtEnv, j->second.object.get());
     319             :             }
     320             :         }
     321           0 :         factory_->removeBridge(this);
     322           0 :         for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
     323             :             try {
     324           0 :                 (*i)->disposing(
     325             :                     css::lang::EventObject(
     326           0 :                         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           0 :         }
     333             :     }
     334           0 :     if (final) {
     335           0 :         uno_threadpool_destroy(tp);
     336             :     }
     337             :     {
     338           0 :         osl::MutexGuard g(mutex_);
     339           0 :         if (final) {
     340           0 :             threadPool_ = 0;
     341           0 :         }
     342             :     }
     343           0 :     terminated_.set();
     344             : }
     345             : 
     346           0 : css::uno::Reference< css::connection::XConnection > Bridge::getConnection()
     347             :     const
     348             : {
     349           0 :     return connection_;
     350             : }
     351             : 
     352           0 : css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider()
     353             :     const
     354             : {
     355           0 :     return provider_;
     356             : }
     357             : 
     358           0 : css::uno::Mapping & Bridge::getCppToBinaryMapping() {
     359           0 :     return cppToBinaryMapping_;
     360             : }
     361             : 
     362           0 : BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
     363           0 :     css::uno::Any in(cppAny);
     364           0 :     BinaryAny out;
     365           0 :     out.~BinaryAny();
     366             :     uno_copyAndConvertData(
     367           0 :         out.get(), &in,
     368           0 :         css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
     369           0 :         cppToBinaryMapping_.get());
     370           0 :     return out;
     371             : }
     372             : 
     373           0 : uno_ThreadPool Bridge::getThreadPool() {
     374           0 :     osl::MutexGuard g(mutex_);
     375           0 :     checkDisposed();
     376             :     assert(threadPool_ != 0);
     377           0 :     return threadPool_;
     378             : }
     379             : 
     380           0 : rtl::Reference< Writer > Bridge::getWriter() {
     381           0 :     osl::MutexGuard g(mutex_);
     382           0 :     checkDisposed();
     383             :     assert(writer_.is());
     384           0 :     return writer_;
     385             : }
     386             : 
     387           0 : css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
     388             :     OUString const & oid, css::uno::TypeDescription const & type)
     389             : {
     390             :     assert(type.is());
     391           0 :     if (oid.isEmpty()) {
     392           0 :         return css::uno::UnoInterfaceReference();
     393             :     }
     394           0 :     css::uno::UnoInterfaceReference obj(findStub(oid, type));
     395           0 :     if (!obj.is()) {
     396           0 :         binaryUno_.get()->pExtEnv->getRegisteredInterface(
     397           0 :             binaryUno_.get()->pExtEnv,
     398             :             reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
     399           0 :             reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
     400           0 :         if (obj.is()) {
     401           0 :             makeReleaseCall(oid, type);
     402             :         } else {
     403           0 :             obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
     404             :             {
     405           0 :                 osl::MutexGuard g(mutex_);
     406             :                 assert(proxies_ < std::numeric_limits< std::size_t >::max());
     407           0 :                 ++proxies_;
     408             :             }
     409           0 :             binaryUno_.get()->pExtEnv->registerProxyInterface(
     410           0 :                 binaryUno_.get()->pExtEnv,
     411             :                 reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
     412             :                 oid.pData,
     413             :                 reinterpret_cast< typelib_InterfaceTypeDescription * >(
     414           0 :                     type.get()));
     415             :         }
     416             :     }
     417           0 :     return obj;
     418             : }
     419             : 
     420           0 : OUString Bridge::registerOutgoingInterface(
     421             :     css::uno::UnoInterfaceReference const & object,
     422             :     css::uno::TypeDescription const & type)
     423             : {
     424             :     assert(type.is());
     425           0 :     if (!object.is()) {
     426           0 :         return OUString();
     427             :     }
     428           0 :     OUString oid;
     429           0 :     if (!Proxy::isProxy(this, object, &oid)) {
     430           0 :         binaryUno_.get()->pExtEnv->getObjectIdentifier(
     431           0 :             binaryUno_.get()->pExtEnv, &oid.pData, object.get());
     432           0 :         osl::MutexGuard g(mutex_);
     433           0 :         Stubs::iterator i(stubs_.find(oid));
     434           0 :         Stub newStub;
     435           0 :         Stub * stub = i == stubs_.end() ? &newStub : &i->second;
     436           0 :         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           0 :         if (j == stub->end()) {
     440           0 :             j = stub->insert(Stub::value_type(type, SubStub())).first;
     441           0 :             if (stub == &newStub) {
     442           0 :                 i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
     443           0 :                 std::swap(i->second, newStub);
     444           0 :                 j = i->second.find(type);
     445             :                 assert(j !=  i->second.end());
     446             :             }
     447           0 :             j->second.object = object;
     448           0 :             j->second.references = 1;
     449           0 :             binaryUno_.get()->pExtEnv->registerInterface(
     450           0 :                 binaryUno_.get()->pExtEnv,
     451           0 :                 reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
     452             :                 oid.pData,
     453             :                 reinterpret_cast< typelib_InterfaceTypeDescription * >(
     454           0 :                     type.get()));
     455             :         } else {
     456             :             assert(stub != &newStub);
     457           0 :             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           0 :             ++j->second.references;
     463           0 :         }
     464             :     }
     465           0 :     return oid;
     466             : }
     467             : 
     468           0 : css::uno::UnoInterfaceReference Bridge::findStub(
     469             :     OUString const & oid, css::uno::TypeDescription const & type)
     470             : {
     471             :     assert(!oid.isEmpty() && type.is());
     472           0 :     osl::MutexGuard g(mutex_);
     473           0 :     Stubs::iterator i(stubs_.find(oid));
     474           0 :     if (i != stubs_.end()) {
     475           0 :         Stub::iterator j(i->second.find(type));
     476           0 :         if (j != i->second.end()) {
     477           0 :             return j->second.object;
     478             :         }
     479           0 :         for (j = i->second.begin(); j != i->second.end(); ++j) {
     480           0 :             if (typelib_typedescription_isAssignableFrom(
     481           0 :                     type.get(), j->first.get()))
     482             :             {
     483           0 :                 return j->second.object;
     484             :             }
     485             :         }
     486             :     }
     487           0 :     return css::uno::UnoInterfaceReference();
     488             : }
     489             : 
     490           0 : void Bridge::releaseStub(
     491             :     OUString const & oid, css::uno::TypeDescription const & type)
     492             : {
     493             :     assert(!oid.isEmpty() && type.is());
     494           0 :     css::uno::UnoInterfaceReference obj;
     495             :     bool unused;
     496             :     {
     497           0 :         osl::MutexGuard g(mutex_);
     498           0 :         Stubs::iterator i(stubs_.find(oid));
     499           0 :         if (i == stubs_.end()) {
     500             :             throw css::uno::RuntimeException(
     501             :                 "URP: release unknown stub",
     502           0 :                 css::uno::Reference< css::uno::XInterface >());
     503             :         }
     504           0 :         Stub::iterator j(i->second.find(type));
     505           0 :         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           0 :         --j->second.references;
     512           0 :         if (j->second.references == 0) {
     513           0 :             obj = j->second.object;
     514           0 :             i->second.erase(j);
     515           0 :             if (i->second.empty()) {
     516           0 :                 stubs_.erase(i);
     517             :             }
     518             :         }
     519           0 :         unused = becameUnused();
     520             :     }
     521           0 :     if (obj.is()) {
     522           0 :         binaryUno_.get()->pExtEnv->revokeInterface(
     523           0 :             binaryUno_.get()->pExtEnv, obj.get());
     524             :     }
     525           0 :     terminateWhenUnused(unused);
     526           0 : }
     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           0 : void Bridge::revokeProxy(Proxy & proxy) {
     540           0 :     binaryUno_.get()->pExtEnv->revokeInterface(
     541           0 :         binaryUno_.get()->pExtEnv, &proxy);
     542           0 : }
     543             : 
     544           0 : void Bridge::freeProxy(Proxy & proxy) {
     545             :     try {
     546           0 :         makeReleaseCall(proxy.getOid(), proxy.getType());
     547           0 :     } 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           0 :         osl::MutexGuard g(mutex_);
     556             :         assert(proxies_ > 0);
     557           0 :         --proxies_;
     558           0 :         unused = becameUnused();
     559             :     }
     560           0 :     terminateWhenUnused(unused);
     561           0 : }
     562             : 
     563           0 : void Bridge::incrementCalls(bool normalCall) throw () {
     564           0 :     osl::MutexGuard g(mutex_);
     565             :     assert(calls_ < std::numeric_limits< std::size_t >::max());
     566           0 :     ++calls_;
     567           0 :     normalCall_ |= normalCall;
     568           0 : }
     569             : 
     570           0 : void Bridge::decrementCalls() {
     571             :     bool unused;
     572             :     {
     573           0 :         osl::MutexGuard g(mutex_);
     574             :         assert(calls_ > 0);
     575           0 :         --calls_;
     576           0 :         unused = becameUnused();
     577             :     }
     578           0 :     terminateWhenUnused(unused);
     579           0 : }
     580             : 
     581           0 : void Bridge::incrementActiveCalls() throw () {
     582           0 :     osl::MutexGuard g(mutex_);
     583             :     assert(
     584             :         activeCalls_ <= calls_ &&
     585             :         activeCalls_ < std::numeric_limits< std::size_t >::max());
     586           0 :     ++activeCalls_;
     587           0 :     passive_.reset();
     588           0 : }
     589             : 
     590           0 : void Bridge::decrementActiveCalls() throw () {
     591           0 :     osl::MutexGuard g(mutex_);
     592             :     assert(activeCalls_ <= calls_ && activeCalls_ > 0);
     593           0 :     --activeCalls_;
     594           0 :     if (activeCalls_ == 0) {
     595           0 :         passive_.set();
     596           0 :     }
     597           0 : }
     598             : 
     599           0 : 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           0 :     std::auto_ptr< IncomingReply > resp;
     605             :     {
     606           0 :         uno_ThreadPool tp = getThreadPool();
     607           0 :         AttachThread att(tp);
     608             :         PopOutgoingRequest pop(
     609             :             outgoingRequests_, att.getTid(),
     610           0 :             OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
     611             :         sendRequest(
     612             :             att.getTid(), oid, css::uno::TypeDescription(), member,
     613           0 :             inArguments);
     614           0 :         pop.clear();
     615           0 :         incrementCalls(true);
     616           0 :         incrementActiveCalls();
     617             :         void * job;
     618           0 :         uno_threadpool_enter(tp, &job);
     619           0 :         resp.reset(static_cast< IncomingReply * >(job));
     620           0 :         decrementActiveCalls();
     621           0 :         decrementCalls();
     622             :     }
     623           0 :     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           0 :     *returnValue = resp->returnValue;
     629           0 :     if (!resp->exception) {
     630           0 :         *outArguments = resp->outArguments;
     631             :     }
     632           0 :     return resp->exception;
     633             : }
     634             : 
     635           0 : void Bridge::sendRequestChangeRequest() {
     636             :     assert(mode_ == MODE_REQUESTED);
     637           0 :     random_ = random();
     638           0 :     std::vector< BinaryAny > a;
     639             :     a.push_back(
     640             :         BinaryAny(
     641           0 :             css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
     642           0 :             &random_));
     643           0 :     sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
     644           0 : }
     645             : 
     646           0 : void Bridge::handleRequestChangeReply(
     647             :     bool exception, BinaryAny const & returnValue)
     648             : {
     649             :     try {
     650           0 :         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           0 :         return;
     666             :     }
     667             :     sal_Int32 n = *static_cast< sal_Int32 * >(
     668             :         returnValue.getValue(
     669           0 :             css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
     670           0 :     sal_Int32 exp = 0;
     671           0 :     switch (mode_) {
     672             :     case MODE_REQUESTED:
     673             :     case MODE_REPLY_1:
     674           0 :         exp = 1;
     675           0 :         break;
     676             :     case MODE_REPLY_MINUS1:
     677           0 :         exp = -1;
     678           0 :         mode_ = MODE_REQUESTED;
     679           0 :         break;
     680             :     case MODE_REPLY_0:
     681           0 :         exp = 0;
     682           0 :         mode_ = MODE_WAIT;
     683           0 :         break;
     684             :     default:
     685             :         assert(false); // this cannot happen
     686           0 :         break;
     687             :     }
     688           0 :     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           0 :     decrementCalls();
     694           0 :     switch (exp) {
     695             :     case -1:
     696           0 :         sendRequestChangeRequest();
     697           0 :         break;
     698             :     case 0:
     699           0 :         break;
     700             :     case 1:
     701           0 :         sendCommitChangeRequest();
     702           0 :         break;
     703             :     default:
     704             :         assert(false); // this cannot happen
     705           0 :         break;
     706             :     }
     707             : }
     708             : 
     709           0 : void Bridge::handleCommitChangeReply(
     710             :     bool exception, BinaryAny const & returnValue)
     711             : {
     712           0 :     bool ccMode = true;
     713             :     try {
     714           0 :         throwException(exception, returnValue);
     715           0 :     } catch (const css::bridge::InvalidProtocolChangeException &) {
     716           0 :         ccMode = false;
     717             :     }
     718           0 :     if (ccMode) {
     719           0 :         setCurrentContextMode();
     720             :     }
     721             :     assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
     722           0 :     mode_ = MODE_NORMAL;
     723           0 :     getWriter()->unblock();
     724           0 :     decrementCalls();
     725           0 : }
     726             : 
     727           0 : void Bridge::handleRequestChangeRequest(
     728             :     rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
     729             : {
     730             :     assert(inArguments.size() == 1);
     731           0 :     switch (mode_) {
     732             :     case MODE_REQUESTED:
     733             :         {
     734             :             sal_Int32 n2 = *static_cast< sal_Int32 * >(
     735           0 :                 inArguments[0].getValue(
     736             :                     css::uno::TypeDescription(
     737           0 :                         cppu::UnoType< sal_Int32 >::get())));
     738             :             sal_Int32 ret;
     739           0 :             if (n2 > random_) {
     740           0 :                 ret = 1;
     741           0 :                 mode_ = MODE_REPLY_0;
     742           0 :             } else if (n2 == random_) {
     743           0 :                 ret = -1;
     744           0 :                 mode_ = MODE_REPLY_MINUS1;
     745             :             } else {
     746           0 :                 ret = 0;
     747           0 :                 mode_ = MODE_REPLY_1;
     748             :             }
     749             :             getWriter()->sendDirectReply(
     750             :                 tid, protPropRequest_, false,
     751             :                 BinaryAny(
     752             :                     css::uno::TypeDescription(
     753           0 :                         cppu::UnoType< sal_Int32 >::get()),
     754             :                     &ret),
     755           0 :             std::vector< BinaryAny >());
     756             :             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             :             break;
     770             :         }
     771             :     default:
     772             :         throw css::uno::RuntimeException(
     773             :             "URP: unexpected requestChange request received",
     774           0 :             static_cast< cppu::OWeakObject * >(this));
     775             :     }
     776           0 : }
     777             : 
     778           0 : void Bridge::handleCommitChangeRequest(
     779             :     rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
     780             : {
     781           0 :     bool ccMode = false;
     782           0 :     bool exc = false;
     783           0 :     BinaryAny ret;
     784             :     assert(inArguments.size() == 1);
     785           0 :     css::uno::Sequence< css::bridge::ProtocolProperty > s;
     786           0 :     bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
     787             :     assert(ok);
     788             :     (void) ok; // avoid warnings
     789           0 :     for (sal_Int32 i = 0; i != s.getLength(); ++i) {
     790           0 :         if (s[i].Name == "CurrentContext") {
     791           0 :             ccMode = true;
     792             :         } else {
     793           0 :             ccMode = false;
     794           0 :             exc = true;
     795             :             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           0 :     switch (mode_) {
     805             :     case MODE_WAIT:
     806             :         getWriter()->sendDirectReply(
     807           0 :             tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
     808           0 :         if (ccMode) {
     809           0 :             setCurrentContextMode();
     810           0 :             mode_ = MODE_NORMAL;
     811           0 :             getWriter()->unblock();
     812             :         } else {
     813           0 :             mode_ = MODE_REQUESTED;
     814           0 :             sendRequestChangeRequest();
     815             :         }
     816           0 :         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           0 :     }
     828           0 : }
     829             : 
     830           0 : OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
     831           0 :     OutgoingRequest req(outgoingRequests_.top(tid));
     832           0 :     outgoingRequests_.pop(tid);
     833           0 :     return req;
     834             : }
     835             : 
     836           0 : bool Bridge::isProtocolPropertiesRequest(
     837             :     OUString const & oid, css::uno::TypeDescription const & type) const
     838             : {
     839           0 :     return oid == protPropOid_ && type.equals(protPropType_);
     840             : }
     841             : 
     842           0 : void Bridge::setCurrentContextMode() {
     843           0 :     osl::MutexGuard g(mutex_);
     844           0 :     currentContextMode_ = true;
     845           0 : }
     846             : 
     847           0 : bool Bridge::isCurrentContextMode() {
     848           0 :     osl::MutexGuard g(mutex_);
     849           0 :     return currentContextMode_;
     850             : }
     851             : 
     852           0 : 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           0 :     dispose();
     862           0 : }
     863             : 
     864           0 : css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
     865             :     OUString const & sInstanceName) throw (css::uno::RuntimeException)
     866             : {
     867           0 :     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           0 :     for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
     873           0 :         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           0 :         cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get());
     882           0 :     typelib_TypeDescription * p = ifc.get();
     883           0 :     std::vector< BinaryAny > inArgs;
     884             :     inArgs.push_back(
     885             :         BinaryAny(
     886           0 :             css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
     887           0 :             &p));
     888           0 :     BinaryAny ret;
     889           0 :     std::vector< BinaryAny> outArgs;
     890             :     bool exc = makeCall(
     891             :         sInstanceName,
     892             :         css::uno::TypeDescription(
     893             :             "com.sun.star.uno.XInterface::queryInterface"),
     894           0 :         false, inArgs, &ret, &outArgs);
     895           0 :     throwException(exc, ret);
     896             :     return css::uno::Reference< css::uno::XInterface >(
     897             :         static_cast< css::uno::XInterface * >(
     898             :             binaryToCppMapping_.mapInterface(
     899           0 :                 *static_cast< uno_Interface ** >(ret.getValue(ifc)),
     900           0 :                 ifc.get())),
     901           0 :         css::uno::UNO_REF_NO_ACQUIRE);
     902             : }
     903             : 
     904           0 : OUString Bridge::getName() throw (css::uno::RuntimeException) {
     905           0 :     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           0 : 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           0 :     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           0 :     passive_.wait();
     926           0 : }
     927             : 
     928           0 : void Bridge::addEventListener(
     929             :     css::uno::Reference< css::lang::XEventListener > const & xListener)
     930             :     throw (css::uno::RuntimeException)
     931             : {
     932             :     assert(xListener.is());
     933             :     {
     934           0 :         osl::MutexGuard g(mutex_);
     935             :         assert(state_ != STATE_INITIAL);
     936           0 :         if (state_ == STATE_STARTED) {
     937           0 :             listeners_.push_back(xListener);
     938           0 :             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           0 : void Bridge::sendCommitChangeRequest() {
     958             :     assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
     959           0 :     css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
     960           0 :     s[0].Name = "CurrentContext";
     961           0 :     std::vector< BinaryAny > a;
     962           0 :     a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
     963           0 :     sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
     964           0 : }
     965             : 
     966           0 : 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           0 :     incrementCalls(false);
     973             :     css::uno::TypeDescription member(
     974             :         kind == OutgoingRequest::KIND_REQUEST_CHANGE
     975           0 :         ? protPropRequest_ : protPropCommit_);
     976             :     PopOutgoingRequest pop(
     977           0 :         outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
     978             :     getWriter()->sendDirectRequest(
     979           0 :         protPropTid_, protPropOid_, protPropType_, member, inArguments);
     980           0 :     pop.clear();
     981           0 : }
     982             : 
     983           0 : void Bridge::makeReleaseCall(
     984             :     OUString const & oid, css::uno::TypeDescription const & type)
     985             : {
     986           0 :     AttachThread att(getThreadPool());
     987             :     sendRequest(
     988             :         att.getTid(), oid, type,
     989             :         css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
     990           0 :         std::vector< BinaryAny >());
     991           0 : }
     992             : 
     993           0 : 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           0 :     getWriter()->queueRequest(tid, oid, type, member, inArguments);
    1000           0 : }
    1001             : 
    1002           0 : void Bridge::throwException(bool exception, BinaryAny const & value) {
    1003           0 :     if (exception) {
    1004           0 :         cppu::throwException(mapBinaryToCppAny(value));
    1005             :     }
    1006           0 : }
    1007             : 
    1008           0 : css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
    1009           0 :     BinaryAny in(binaryAny);
    1010           0 :     css::uno::Any out;
    1011           0 :     out.~Any();
    1012             :     uno_copyAndConvertData(
    1013           0 :         &out, in.get(),
    1014           0 :         css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
    1015           0 :         binaryToCppMapping_.get());
    1016           0 :     return out;
    1017             : }
    1018             : 
    1019           0 : bool Bridge::becameUnused() const {
    1020           0 :     return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
    1021             : }
    1022             : 
    1023           0 : void Bridge::terminateWhenUnused(bool unused) {
    1024           0 :     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           0 :         terminate(false);
    1029             :     }
    1030           0 : }
    1031             : 
    1032           0 : void Bridge::checkDisposed() {
    1033             :     assert(state_ != STATE_INITIAL);
    1034           0 :     if (state_ != STATE_STARTED) {
    1035             :         throw css::lang::DisposedException(
    1036             :             "Binary URP bridge already disposed",
    1037           0 :             static_cast< cppu::OWeakObject * >(this));
    1038             :     }
    1039           0 : }
    1040             : 
    1041             : }
    1042             : 
    1043             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10