LCOV - code coverage report
Current view: top level - binaryurp/source - bridge.cxx (source / functions) Hit Total Coverage
Test: commit 0e63ca4fde4e446f346e35849c756a30ca294aab Lines: 414 491 84.3 %
Date: 2014-04-11 Functions: 56 60 93.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "sal/config.h"
      21             : 
      22             : #include <algorithm>
      23             : #include <cassert>
      24             : #include <cstddef>
      25             : #include <limits>
      26             : #include <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          51 : sal_Int32 random() {
      77             :     sal_Int32 n;
      78          51 :     rtlRandomPool pool = rtl_random_createPool();
      79          51 :     rtl_random_getBytes(pool, &n, sizeof n);
      80          51 :     rtl_random_destroyPool(pool);
      81          51 :     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        2006 : extern "C" void SAL_CALL freeProxyCallback(
      91             :     SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pProxy)
      92             : {
      93             :     assert(pProxy != 0);
      94        2006 :     static_cast< Proxy * >(pProxy)->do_free();
      95        2006 : }
      96             : 
      97         102 : bool isThread(salhelper::Thread * thread) {
      98             :     assert(thread != 0);
      99         102 :     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       11855 : AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
     116       11855 :     sal_Sequence * s = 0;
     117       11855 :     uno_getIdOfCurrentThread(&s);
     118       11855 :     tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
     119       11855 :     uno_threadpool_attach(threadPool_);
     120       11855 : }
     121             : 
     122       23710 : AttachThread::~AttachThread() {
     123       11855 :     uno_threadpool_detach(threadPool_);
     124       11855 :     uno_releaseIdFromCurrentThread();
     125       11855 : }
     126             : 
     127       18921 : rtl::ByteSequence AttachThread::getTid() throw () {
     128       18921 :     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        7146 : PopOutgoingRequest::PopOutgoingRequest(
     148             :     OutgoingRequests & requests, rtl::ByteSequence const & tid,
     149             :     OutgoingRequest const & request):
     150        7146 :     requests_(requests), tid_(tid), cleared_(false)
     151             : {
     152        7146 :     requests_.push(tid_, request);
     153        7146 : }
     154             : 
     155       14292 : PopOutgoingRequest::~PopOutgoingRequest() {
     156        7146 :     if (!cleared_) {
     157           0 :         requests_.pop(tid_);
     158             :     }
     159        7146 : }
     160             : 
     161        7146 : void PopOutgoingRequest::clear() {
     162        7146 :     cleared_ = true;
     163        7146 : }
     164             : 
     165             : }
     166             : 
     167      300699 : struct Bridge::SubStub {
     168             :     com::sun::star::uno::UnoInterfaceReference object;
     169             : 
     170             :     sal_uInt32 references;
     171             : };
     172             : 
     173          51 : 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          51 :         RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
     185             :     protPropOid_("UrpProtocolProperties"),
     186             :     protPropType_(
     187             :         cppu::UnoType<
     188          51 :             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         153 :     mode_(MODE_REQUESTED)
     194             : {
     195             :     assert(factory.is() && connection.is());
     196          51 :     if (!binaryUno_.is()) {
     197             :         throw css::uno::RuntimeException(
     198             :             "URP: no binary UNO environment",
     199           0 :             css::uno::Reference< css::uno::XInterface >());
     200             :     }
     201          51 :     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          51 :     passive_.set();
     207          51 : }
     208             : 
     209          51 : void Bridge::start() {
     210          51 :     rtl::Reference< Reader > r(new Reader(this));
     211         102 :     rtl::Reference< Writer > w(new Writer(this));
     212             :     {
     213          51 :         osl::MutexGuard g(mutex_);
     214             :         assert(
     215             :             state_ == STATE_INITIAL && threadPool_ == 0 && !writer_.is() &&
     216             :             !reader_.is());
     217          51 :         threadPool_ = uno_threadpool_create();
     218             :         assert(threadPool_ != 0);
     219          51 :         reader_ = r;
     220          51 :         writer_ = w;
     221          51 :         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          51 :     w->launch();
     230         102 :     r->launch();
     231          51 : }
     232             : 
     233         160 : 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         160 :         rtl::Reference< Reader > r;
     239         210 :         rtl::Reference< Writer > w;
     240             :         bool joinW;
     241         210 :         Listeners ls;
     242             :         {
     243         160 :             osl::ClearableMutexGuard g(mutex_);
     244         160 :             switch (state_) {
     245             :             case STATE_INITIAL: // via ~Bridge -> dispose -> terminate
     246             :             case STATE_FINAL:
     247         106 :                 return;
     248             :             case STATE_STARTED:
     249          50 :                 break;
     250             :             case STATE_TERMINATED:
     251           4 :                 if (final) {
     252           3 :                     g.clear();
     253           3 :                     terminated_.wait();
     254             :                     {
     255           3 :                         osl::MutexGuard g2(mutex_);
     256           3 :                         tp = threadPool_;
     257           3 :                         threadPool_ = 0;
     258           3 :                         if (reader_.is()) {
     259           2 :                             if (!isThread(reader_.get())) {
     260           1 :                                 r = reader_;
     261             :                             }
     262           2 :                             reader_.clear();
     263             :                         }
     264           3 :                         if (writer_.is()) {
     265           0 :                             if (!isThread(writer_.get())) {
     266           0 :                                 w = writer_;
     267             :                             }
     268           0 :                             writer_.clear();
     269             :                         }
     270           3 :                         state_ = STATE_FINAL;
     271             :                     }
     272             :                     assert(!(r.is() && w.is()));
     273           3 :                     if (r.is()) {
     274           1 :                         r->join();
     275           2 :                     } else if (w.is()) {
     276           0 :                         w->join();
     277             :                     }
     278           3 :                     if (tp != 0) {
     279           3 :                         uno_threadpool_destroy(tp);
     280             :                     }
     281             :                 }
     282           4 :                 return;
     283             :             }
     284          50 :             tp = threadPool_;
     285             :             assert(!(final && isThread(reader_.get())));
     286          50 :             if (!isThread(reader_.get())) {
     287          48 :                 std::swap(reader_, r);
     288             :             }
     289          50 :             w = writer_;
     290          50 :             joinW = !isThread(writer_.get());
     291             :             assert(!final || joinW);
     292          50 :             if (joinW) {
     293          50 :                 writer_.clear();
     294             :             }
     295          50 :             ls.swap(listeners_);
     296          50 :             state_ = final ? STATE_FINAL : STATE_TERMINATED;
     297             :         }
     298             :         try {
     299          50 :             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          50 :         w->stop();
     305          50 :         if (r.is()) {
     306          48 :             r->join();
     307             :         }
     308          50 :         if (joinW) {
     309          50 :             w->join();
     310             :         }
     311             :         assert(tp != 0);
     312          50 :         uno_threadpool_dispose(tp);
     313          50 :         Stubs s;
     314             :         {
     315          50 :             osl::MutexGuard g(mutex_);
     316          50 :             s.swap(stubs_);
     317             :         }
     318       12851 :         for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
     319       33873 :             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       21072 :                 binaryUno_.get()->pExtEnv->revokeInterface(
     326       21072 :                     binaryUno_.get()->pExtEnv, j->second.object.get());
     327             :             }
     328             :         }
     329          50 :         factory_->removeBridge(this);
     330          51 :         for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
     331             :             try {
     332           1 :                 (*i)->disposing(
     333             :                     css::lang::EventObject(
     334           1 :                         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         100 :         }
     341             :     }
     342          50 :     if (final) {
     343          47 :         uno_threadpool_destroy(tp);
     344             :     }
     345             :     {
     346          50 :         osl::MutexGuard g(mutex_);
     347          50 :         if (final) {
     348          47 :             threadPool_ = 0;
     349          50 :         }
     350             :     }
     351          50 :     terminated_.set();
     352             : }
     353             : 
     354      207650 : css::uno::Reference< css::connection::XConnection > Bridge::getConnection()
     355             :     const
     356             : {
     357      207650 :     return connection_;
     358             : }
     359             : 
     360          67 : css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider()
     361             :     const
     362             : {
     363          67 :     return provider_;
     364             : }
     365             : 
     366          69 : css::uno::Mapping & Bridge::getCppToBinaryMapping() {
     367          69 :     return cppToBinaryMapping_;
     368             : }
     369             : 
     370          29 : BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
     371          29 :     css::uno::Any in(cppAny);
     372          29 :     BinaryAny out;
     373          29 :     out.~BinaryAny();
     374             :     uno_copyAndConvertData(
     375          29 :         out.get(), &in,
     376          29 :         css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
     377          87 :         cppToBinaryMapping_.get());
     378          29 :     return out;
     379             : }
     380             : 
     381      269010 : uno_ThreadPool Bridge::getThreadPool() {
     382      269010 :     osl::MutexGuard g(mutex_);
     383      269010 :     checkDisposed();
     384             :     assert(threadPool_ != 0);
     385      268976 :     return threadPool_;
     386             : }
     387             : 
     388      207658 : rtl::Reference< Writer > Bridge::getWriter() {
     389      207658 :     osl::MutexGuard g(mutex_);
     390      207658 :     checkDisposed();
     391             :     assert(writer_.is());
     392      207652 :     return writer_;
     393             : }
     394             : 
     395      207735 : css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
     396             :     OUString const & oid, css::uno::TypeDescription const & type)
     397             : {
     398             :     assert(type.is());
     399      207735 :     if (oid.isEmpty()) {
     400      196641 :         return css::uno::UnoInterfaceReference();
     401             :     }
     402       11094 :     css::uno::UnoInterfaceReference obj(findStub(oid, type));
     403       11094 :     if (!obj.is()) {
     404        4830 :         binaryUno_.get()->pExtEnv->getRegisteredInterface(
     405        4830 :             binaryUno_.get()->pExtEnv,
     406             :             reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
     407        9660 :             reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
     408        4830 :         if (obj.is()) {
     409        2815 :             makeReleaseCall(oid, type);
     410             :         } else {
     411        2015 :             obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
     412             :             {
     413        2015 :                 osl::MutexGuard g(mutex_);
     414             :                 assert(proxies_ < std::numeric_limits< std::size_t >::max());
     415        2015 :                 ++proxies_;
     416             :             }
     417        2015 :             binaryUno_.get()->pExtEnv->registerProxyInterface(
     418        2015 :                 binaryUno_.get()->pExtEnv,
     419             :                 reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
     420             :                 oid.pData,
     421             :                 reinterpret_cast< typelib_InterfaceTypeDescription * >(
     422        4030 :                     type.get()));
     423             :         }
     424             :     }
     425       11094 :     return obj;
     426             : }
     427             : 
     428       84162 : OUString Bridge::registerOutgoingInterface(
     429             :     css::uno::UnoInterfaceReference const & object,
     430             :     css::uno::TypeDescription const & type)
     431             : {
     432             :     assert(type.is());
     433       84162 :     if (!object.is()) {
     434        8477 :         return OUString();
     435             :     }
     436       75685 :     OUString oid;
     437       75685 :     if (!Proxy::isProxy(this, object, &oid)) {
     438       75553 :         binaryUno_.get()->pExtEnv->getObjectIdentifier(
     439       75553 :             binaryUno_.get()->pExtEnv, &oid.pData, object.get());
     440       75553 :         osl::MutexGuard g(mutex_);
     441       75553 :         Stubs::iterator i(stubs_.find(oid));
     442      151106 :         Stub newStub;
     443       75553 :         Stub * stub = i == stubs_.end() ? &newStub : &i->second;
     444       75553 :         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       75553 :         if (j == stub->end()) {
     448       50117 :             j = stub->insert(Stub::value_type(type, SubStub())).first;
     449       50117 :             if (stub == &newStub) {
     450       31619 :                 i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
     451       31619 :                 std::swap(i->second, newStub);
     452       31619 :                 j = i->second.find(type);
     453             :                 assert(j !=  i->second.end());
     454             :             }
     455       50117 :             j->second.object = object;
     456       50117 :             j->second.references = 1;
     457       50117 :             binaryUno_.get()->pExtEnv->registerInterface(
     458       50117 :                 binaryUno_.get()->pExtEnv,
     459       50117 :                 reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
     460             :                 oid.pData,
     461             :                 reinterpret_cast< typelib_InterfaceTypeDescription * >(
     462      150351 :                     type.get()));
     463             :         } else {
     464             :             assert(stub != &newStub);
     465       25436 :             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       25436 :             ++j->second.references;
     471       75553 :         }
     472             :     }
     473       75685 :     return oid;
     474             : }
     475             : 
     476      206693 : css::uno::UnoInterfaceReference Bridge::findStub(
     477             :     OUString const & oid, css::uno::TypeDescription const & type)
     478             : {
     479             :     assert(!oid.isEmpty() && type.is());
     480      206693 :     osl::MutexGuard g(mutex_);
     481      206693 :     Stubs::iterator i(stubs_.find(oid));
     482      206693 :     if (i != stubs_.end()) {
     483      201796 :         Stub::iterator j(i->second.find(type));
     484      201796 :         if (j != i->second.end()) {
     485      400479 :             return j->second.object;
     486             :         }
     487        3181 :         for (j = i->second.begin(); j != i->second.end(); ++j) {
     488        3181 :             if (typelib_typedescription_isAssignableFrom(
     489        3181 :                     type.get(), j->first.get()))
     490             :             {
     491        3113 :                 return j->second.object;
     492             :             }
     493             :         }
     494             :     }
     495        4897 :     return css::uno::UnoInterfaceReference();
     496             : }
     497             : 
     498       54456 : void Bridge::releaseStub(
     499             :     OUString const & oid, css::uno::TypeDescription const & type)
     500             : {
     501             :     assert(!oid.isEmpty() && type.is());
     502       54456 :     css::uno::UnoInterfaceReference obj;
     503             :     bool unused;
     504             :     {
     505       54456 :         osl::MutexGuard g(mutex_);
     506       54456 :         Stubs::iterator i(stubs_.find(oid));
     507       54456 :         if (i == stubs_.end()) {
     508             :             throw css::uno::RuntimeException(
     509             :                 "URP: release unknown stub",
     510           0 :                 css::uno::Reference< css::uno::XInterface >());
     511             :         }
     512       54456 :         Stub::iterator j(i->second.find(type));
     513       54456 :         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       54456 :         --j->second.references;
     520       54456 :         if (j->second.references == 0) {
     521       29042 :             obj = j->second.object;
     522       29042 :             i->second.erase(j);
     523       29042 :             if (i->second.empty()) {
     524       18816 :                 stubs_.erase(i);
     525             :             }
     526             :         }
     527       54456 :         unused = becameUnused();
     528             :     }
     529       54456 :     if (obj.is()) {
     530       29042 :         binaryUno_.get()->pExtEnv->revokeInterface(
     531       29042 :             binaryUno_.get()->pExtEnv, obj.get());
     532             :     }
     533       54456 :     terminateWhenUnused(unused);
     534       54456 : }
     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        2006 : void Bridge::revokeProxy(Proxy & proxy) {
     548        2006 :     binaryUno_.get()->pExtEnv->revokeInterface(
     549        2006 :         binaryUno_.get()->pExtEnv, &proxy);
     550        2006 : }
     551             : 
     552        2006 : void Bridge::freeProxy(Proxy & proxy) {
     553             :     try {
     554        2038 :         makeReleaseCall(proxy.getOid(), proxy.getType());
     555          32 :     } 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        2006 :         osl::MutexGuard g(mutex_);
     564             :         assert(proxies_ > 0);
     565        2006 :         --proxies_;
     566        2006 :         unused = becameUnused();
     567             :     }
     568        2006 :     terminateWhenUnused(unused);
     569        2006 : }
     570             : 
     571      257274 : void Bridge::incrementCalls(bool normalCall) throw () {
     572      257274 :     osl::MutexGuard g(mutex_);
     573             :     assert(calls_ < std::numeric_limits< std::size_t >::max());
     574      257274 :     ++calls_;
     575      257274 :     normalCall_ |= normalCall;
     576      257274 : }
     577             : 
     578      257266 : void Bridge::decrementCalls() {
     579             :     bool unused;
     580             :     {
     581      257266 :         osl::MutexGuard g(mutex_);
     582             :         assert(calls_ > 0);
     583      257266 :         --calls_;
     584      257266 :         unused = becameUnused();
     585             :     }
     586      257265 :     terminateWhenUnused(unused);
     587      257265 : }
     588             : 
     589      202665 : void Bridge::incrementActiveCalls() throw () {
     590      202665 :     osl::MutexGuard g(mutex_);
     591             :     assert(
     592             :         activeCalls_ <= calls_ &&
     593             :         activeCalls_ < std::numeric_limits< std::size_t >::max());
     594      202665 :     ++activeCalls_;
     595      202665 :     passive_.reset();
     596      202665 : }
     597             : 
     598      202665 : void Bridge::decrementActiveCalls() throw () {
     599      202665 :     osl::MutexGuard g(mutex_);
     600             :     assert(activeCalls_ <= calls_ && activeCalls_ > 0);
     601      202665 :     --activeCalls_;
     602      202665 :     if (activeCalls_ == 0) {
     603      191368 :         passive_.set();
     604      202665 :     }
     605      202665 : }
     606             : 
     607        7068 : 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        7068 :     boost::scoped_ptr< IncomingReply > resp;
     613             :     {
     614        7068 :         uno_ThreadPool tp = getThreadPool();
     615        7066 :         AttachThread att(tp);
     616             :         PopOutgoingRequest pop(
     617             :             outgoingRequests_, att.getTid(),
     618       14132 :             OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
     619             :         sendRequest(
     620             :             att.getTid(), oid, css::uno::TypeDescription(), member,
     621        7066 :             inArguments);
     622        7066 :         pop.clear();
     623        7066 :         incrementCalls(true);
     624        7066 :         incrementActiveCalls();
     625             :         void * job;
     626        7066 :         uno_threadpool_enter(tp, &job);
     627        7066 :         resp.reset(static_cast< IncomingReply * >(job));
     628        7066 :         decrementActiveCalls();
     629       14132 :         decrementCalls();
     630             :     }
     631        7066 :     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        7066 :     *returnValue = resp->returnValue;
     637        7066 :     if (!resp->exception) {
     638        7050 :         *outArguments = resp->outArguments;
     639             :     }
     640        7068 :     return resp->exception;
     641             : }
     642             : 
     643          51 : void Bridge::sendRequestChangeRequest() {
     644             :     assert(mode_ == MODE_REQUESTED);
     645          51 :     random_ = random();
     646          51 :     std::vector< BinaryAny > a;
     647             :     a.push_back(
     648             :         BinaryAny(
     649          51 :             css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
     650         102 :             &random_));
     651          51 :     sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
     652          51 : }
     653             : 
     654          51 : void Bridge::handleRequestChangeReply(
     655             :     bool exception, BinaryAny const & returnValue)
     656             : {
     657             :     try {
     658          51 :         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          51 :         return;
     674             :     }
     675             :     sal_Int32 n = *static_cast< sal_Int32 * >(
     676             :         returnValue.getValue(
     677          51 :             css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
     678          51 :     sal_Int32 exp = 0;
     679          51 :     switch (mode_) {
     680             :     case MODE_REQUESTED:
     681             :     case MODE_REPLY_1:
     682          29 :         exp = 1;
     683          29 :         break;
     684             :     case MODE_REPLY_MINUS1:
     685           0 :         exp = -1;
     686           0 :         mode_ = MODE_REQUESTED;
     687           0 :         break;
     688             :     case MODE_REPLY_0:
     689          22 :         exp = 0;
     690          22 :         mode_ = MODE_WAIT;
     691          22 :         break;
     692             :     default:
     693             :         assert(false); // this cannot happen
     694           0 :         break;
     695             :     }
     696          51 :     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          51 :     decrementCalls();
     702          51 :     switch (exp) {
     703             :     case -1:
     704           0 :         sendRequestChangeRequest();
     705           0 :         break;
     706             :     case 0:
     707          22 :         break;
     708             :     case 1:
     709          29 :         sendCommitChangeRequest();
     710          29 :         break;
     711             :     default:
     712             :         assert(false); // this cannot happen
     713           0 :         break;
     714             :     }
     715             : }
     716             : 
     717          29 : void Bridge::handleCommitChangeReply(
     718             :     bool exception, BinaryAny const & returnValue)
     719             : {
     720          29 :     bool ccMode = true;
     721             :     try {
     722          29 :         throwException(exception, returnValue);
     723           0 :     } catch (const css::bridge::InvalidProtocolChangeException &) {
     724           0 :         ccMode = false;
     725             :     }
     726          29 :     if (ccMode) {
     727          29 :         setCurrentContextMode();
     728             :     }
     729             :     assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
     730          29 :     mode_ = MODE_NORMAL;
     731          29 :     getWriter()->unblock();
     732          29 :     decrementCalls();
     733          29 : }
     734             : 
     735          51 : void Bridge::handleRequestChangeRequest(
     736             :     rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
     737             : {
     738             :     assert(inArguments.size() == 1);
     739          51 :     switch (mode_) {
     740             :     case MODE_REQUESTED:
     741             :         {
     742             :             sal_Int32 n2 = *static_cast< sal_Int32 * >(
     743          51 :                 inArguments[0].getValue(
     744             :                     css::uno::TypeDescription(
     745         102 :                         cppu::UnoType< sal_Int32 >::get())));
     746             :             sal_Int32 ret;
     747          51 :             if (n2 > random_) {
     748          22 :                 ret = 1;
     749          22 :                 mode_ = MODE_REPLY_0;
     750          29 :             } else if (n2 == random_) {
     751           0 :                 ret = -1;
     752           0 :                 mode_ = MODE_REPLY_MINUS1;
     753             :             } else {
     754          29 :                 ret = 0;
     755          29 :                 mode_ = MODE_REPLY_1;
     756             :             }
     757             :             getWriter()->sendDirectReply(
     758             :                 tid, protPropRequest_, false,
     759             :                 BinaryAny(
     760             :                     css::uno::TypeDescription(
     761          51 :                         cppu::UnoType< sal_Int32 >::get()),
     762             :                     &ret),
     763         102 :             std::vector< BinaryAny >());
     764          51 :             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          51 : }
     785             : 
     786          22 : void Bridge::handleCommitChangeRequest(
     787             :     rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
     788             : {
     789          22 :     bool ccMode = false;
     790          22 :     bool exc = false;
     791          22 :     BinaryAny ret;
     792             :     assert(inArguments.size() == 1);
     793          44 :     css::uno::Sequence< css::bridge::ProtocolProperty > s;
     794          22 :     bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
     795             :     assert(ok);
     796             :     (void) ok; // avoid warnings
     797          44 :     for (sal_Int32 i = 0; i != s.getLength(); ++i) {
     798          22 :         if (s[i].Name == "CurrentContext") {
     799          22 :             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          22 :     switch (mode_) {
     813             :     case MODE_WAIT:
     814             :         getWriter()->sendDirectReply(
     815          22 :             tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
     816          22 :         if (ccMode) {
     817          22 :             setCurrentContextMode();
     818          22 :             mode_ = MODE_NORMAL;
     819          22 :             getWriter()->unblock();
     820             :         } else {
     821           0 :             mode_ = MODE_REQUESTED;
     822           0 :             sendRequestChangeRequest();
     823             :         }
     824          22 :         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          22 :     }
     836          22 : }
     837             : 
     838        7146 : OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
     839        7146 :     OutgoingRequest req(outgoingRequests_.top(tid));
     840        7146 :     outgoingRequests_.pop(tid);
     841        7146 :     return req;
     842             : }
     843             : 
     844      250128 : bool Bridge::isProtocolPropertiesRequest(
     845             :     OUString const & oid, css::uno::TypeDescription const & type) const
     846             : {
     847      250128 :     return oid == protPropOid_ && type.equals(protPropType_);
     848             : }
     849             : 
     850          51 : void Bridge::setCurrentContextMode() {
     851          51 :     osl::MutexGuard g(mutex_);
     852          51 :     currentContextMode_ = true;
     853          51 : }
     854             : 
     855      202665 : bool Bridge::isCurrentContextMode() {
     856      202665 :     osl::MutexGuard g(mutex_);
     857      202665 :     return currentContextMode_;
     858             : }
     859             : 
     860         141 : 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          47 :     dispose();
     870          94 : }
     871             : 
     872           2 : css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
     873             :     OUString const & sInstanceName) throw (css::uno::RuntimeException, std::exception)
     874             : {
     875           2 :     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          49 :     for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
     881          47 :         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           2 :         cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get());
     890           2 :     typelib_TypeDescription * p = ifc.get();
     891           4 :     std::vector< BinaryAny > inArgs;
     892             :     inArgs.push_back(
     893             :         BinaryAny(
     894           2 :             css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
     895           2 :             &p));
     896           4 :     BinaryAny ret;
     897           4 :     std::vector< BinaryAny> outArgs;
     898             :     bool exc = makeCall(
     899             :         sInstanceName,
     900             :         css::uno::TypeDescription(
     901             :             "com.sun.star.uno.XInterface::queryInterface"),
     902           2 :         false, inArgs, &ret, &outArgs);
     903           2 :     throwException(exc, ret);
     904             :     return css::uno::Reference< css::uno::XInterface >(
     905             :         static_cast< css::uno::XInterface * >(
     906             :             binaryToCppMapping_.mapInterface(
     907           2 :                 *static_cast< uno_Interface ** >(ret.getValue(ifc)),
     908           4 :                 ifc.get())),
     909           4 :         css::uno::UNO_REF_NO_ACQUIRE);
     910             : }
     911             : 
     912          50 : OUString Bridge::getName() throw (css::uno::RuntimeException, std::exception) {
     913          50 :     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          95 : 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          95 :     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          95 :     passive_.wait();
     934          95 : }
     935             : 
     936           1 : 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           1 :         osl::MutexGuard g(mutex_);
     943             :         assert(state_ != STATE_INITIAL);
     944           1 :         if (state_ == STATE_STARTED) {
     945           1 :             listeners_.push_back(xListener);
     946           2 :             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          29 : void Bridge::sendCommitChangeRequest() {
     966             :     assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
     967          29 :     css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
     968          29 :     s[0].Name = "CurrentContext";
     969          58 :     std::vector< BinaryAny > a;
     970          29 :     a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
     971          58 :     sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
     972          29 : }
     973             : 
     974          80 : 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          80 :     incrementCalls(false);
     981             :     css::uno::TypeDescription member(
     982             :         kind == OutgoingRequest::KIND_REQUEST_CHANGE
     983          80 :         ? protPropRequest_ : protPropCommit_);
     984             :     PopOutgoingRequest pop(
     985         160 :         outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
     986             :     getWriter()->sendDirectRequest(
     987          80 :         protPropTid_, protPropOid_, protPropType_, member, inArguments);
     988         160 :     pop.clear();
     989          80 : }
     990             : 
     991        4821 : void Bridge::makeReleaseCall(
     992             :     OUString const & oid, css::uno::TypeDescription const & type)
     993             : {
     994        4821 :     AttachThread att(getThreadPool());
     995             :     sendRequest(
     996             :         att.getTid(), oid, type,
     997             :         css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
     998        4789 :         std::vector< BinaryAny >());
     999        4789 : }
    1000             : 
    1001       11855 : 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       11855 :     getWriter()->queueRequest(tid, oid, type, member, inArguments);
    1008       11855 : }
    1009             : 
    1010          82 : void Bridge::throwException(bool exception, BinaryAny const & value) {
    1011          82 :     if (exception) {
    1012           0 :         cppu::throwException(mapBinaryToCppAny(value));
    1013             :     }
    1014          82 : }
    1015             : 
    1016          22 : css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
    1017          22 :     BinaryAny in(binaryAny);
    1018          22 :     css::uno::Any out;
    1019          22 :     out.~Any();
    1020             :     uno_copyAndConvertData(
    1021          22 :         &out, in.get(),
    1022          22 :         css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
    1023          66 :         binaryToCppMapping_.get());
    1024          22 :     return out;
    1025             : }
    1026             : 
    1027      313728 : bool Bridge::becameUnused() const {
    1028      313728 :     return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
    1029             : }
    1030             : 
    1031      313726 : void Bridge::terminateWhenUnused(bool unused) {
    1032      313726 :     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           7 :         terminate(false);
    1037             :     }
    1038      313726 : }
    1039             : 
    1040      476668 : void Bridge::checkDisposed() {
    1041             :     assert(state_ != STATE_INITIAL);
    1042      476668 :     if (state_ != STATE_STARTED) {
    1043             :         throw css::lang::DisposedException(
    1044             :             "Binary URP bridge already disposed",
    1045          40 :             static_cast< cppu::OWeakObject * >(this));
    1046             :     }
    1047      476628 : }
    1048             : 
    1049             : }
    1050             : 
    1051             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10