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

Generated by: LCOV version 1.10