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