fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / binaryurp / source / bridge.cxx
blobf27f37702adbd28a311f19302c932fd58de013b4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "sal/config.h"
22 #include <algorithm>
23 #include <cassert>
24 #include <cstddef>
25 #include <limits>
26 #include <memory>
27 #include <vector>
29 #include "boost/noncopyable.hpp"
30 #include "com/sun/star/bridge/InvalidProtocolChangeException.hpp"
31 #include "com/sun/star/bridge/XBridge.hpp"
32 #include "com/sun/star/bridge/XInstanceProvider.hpp"
33 #include "com/sun/star/bridge/XProtocolProperties.hpp"
34 #include "com/sun/star/connection/XConnection.hpp"
35 #include "com/sun/star/io/IOException.hpp"
36 #include "com/sun/star/lang/DisposedException.hpp"
37 #include "com/sun/star/lang/EventObject.hpp"
38 #include "com/sun/star/lang/XEventListener.hpp"
39 #include "com/sun/star/uno/Reference.hxx"
40 #include "com/sun/star/uno/RuntimeException.hpp"
41 #include "com/sun/star/uno/Sequence.hxx"
42 #include "com/sun/star/uno/XInterface.hpp"
43 #include "cppuhelper/exc_hlp.hxx"
44 #include "cppuhelper/weak.hxx"
45 #include "osl/mutex.hxx"
46 #include "osl/thread.hxx"
47 #include "rtl/byteseq.hxx"
48 #include "rtl/random.h"
49 #include "rtl/ref.hxx"
50 #include "rtl/ustrbuf.hxx"
51 #include "rtl/ustring.h"
52 #include "rtl/ustring.hxx"
53 #include "sal/log.hxx"
54 #include "sal/types.h"
55 #include "typelib/typeclass.h"
56 #include "typelib/typedescription.h"
57 #include "typelib/typedescription.hxx"
58 #include "uno/dispatcher.hxx"
59 #include "uno/environment.hxx"
60 #include "uno/lbnames.h"
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"
72 namespace binaryurp {
74 namespace {
76 sal_Int32 random() {
77 sal_Int32 n;
78 rtlRandomPool pool = rtl_random_createPool();
79 rtl_random_getBytes(pool, &n, sizeof n);
80 rtl_random_destroyPool(pool);
81 return n;
84 OUString toString(css::uno::TypeDescription const & type) {
85 typelib_TypeDescription * d = type.get();
86 assert(d != 0 && d->pTypeName != 0);
87 return OUString(d->pTypeName);
90 extern "C" void SAL_CALL freeProxyCallback(
91 SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pProxy)
93 assert(pProxy != 0);
94 static_cast< Proxy * >(pProxy)->do_free();
97 bool isThread(salhelper::Thread * thread) {
98 assert(thread != 0);
99 return osl::Thread::getCurrentIdentifier() == thread->getIdentifier();
102 class AttachThread: private boost::noncopyable {
103 public:
104 explicit AttachThread(uno_ThreadPool threadPool);
106 ~AttachThread();
108 rtl::ByteSequence getTid() throw ();
110 private:
111 uno_ThreadPool threadPool_;
112 rtl::ByteSequence tid_;
115 AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
116 sal_Sequence * s = 0;
117 uno_getIdOfCurrentThread(&s);
118 tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
119 uno_threadpool_attach(threadPool_);
122 AttachThread::~AttachThread() {
123 uno_threadpool_detach(threadPool_);
124 uno_releaseIdFromCurrentThread();
127 rtl::ByteSequence AttachThread::getTid() throw () {
128 return tid_;
131 class PopOutgoingRequest: private boost::noncopyable {
132 public:
133 PopOutgoingRequest(
134 OutgoingRequests & requests, rtl::ByteSequence const & tid,
135 OutgoingRequest const & request);
137 ~PopOutgoingRequest();
139 void clear();
141 private:
142 OutgoingRequests & requests_;
143 rtl::ByteSequence tid_;
144 bool cleared_;
147 PopOutgoingRequest::PopOutgoingRequest(
148 OutgoingRequests & requests, rtl::ByteSequence const & tid,
149 OutgoingRequest const & request):
150 requests_(requests), tid_(tid), cleared_(false)
152 requests_.push(tid_, request);
155 PopOutgoingRequest::~PopOutgoingRequest() {
156 if (!cleared_) {
157 requests_.pop(tid_);
161 void PopOutgoingRequest::clear() {
162 cleared_ = true;
167 struct Bridge::SubStub {
168 com::sun::star::uno::UnoInterfaceReference object;
170 sal_uInt32 references;
173 Bridge::Bridge(
174 rtl::Reference< BridgeFactory > const & factory, OUString const & name,
175 css::uno::Reference< css::connection::XConnection > const & connection,
176 css::uno::Reference< css::bridge::XInstanceProvider > const & provider):
177 factory_(factory), name_(name), connection_(connection),
178 provider_(provider),
179 binaryUno_(UNO_LB_UNO),
180 cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO),
181 binaryToCppMapping_(UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME),
182 protPropTid_(
183 reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"),
184 RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
185 protPropOid_("UrpProtocolProperties"),
186 protPropType_(
187 cppu::UnoType<
188 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 mode_(MODE_REQUESTED)
195 assert(factory.is() && connection.is());
196 if (!binaryUno_.is()) {
197 throw css::uno::RuntimeException(
198 "URP: no binary UNO environment",
199 css::uno::Reference< css::uno::XInterface >());
201 if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) {
202 throw css::uno::RuntimeException(
203 "URP: no C++ UNO mapping",
204 css::uno::Reference< css::uno::XInterface >());
206 passive_.set();
209 void Bridge::start() {
210 rtl::Reference< Reader > r(new Reader(this));
211 rtl::Reference< Writer > w(new Writer(this));
213 osl::MutexGuard g(mutex_);
214 assert(
215 state_ == STATE_INITIAL && threadPool_ == 0 && !writer_.is() &&
216 !reader_.is());
217 threadPool_ = uno_threadpool_create();
218 assert(threadPool_ != 0);
219 reader_ = r;
220 writer_ = w;
221 state_ = STATE_STARTED;
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 w->launch();
230 r->launch();
233 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:
238 rtl::Reference< Reader > r;
239 rtl::Reference< Writer > w;
240 bool joinW;
241 Listeners ls;
243 osl::ClearableMutexGuard g(mutex_);
244 switch (state_) {
245 case STATE_INITIAL: // via ~Bridge -> dispose -> terminate
246 case STATE_FINAL:
247 return;
248 case STATE_STARTED:
249 break;
250 case STATE_TERMINATED:
251 if (final) {
252 g.clear();
253 terminated_.wait();
255 osl::MutexGuard g2(mutex_);
256 tp = threadPool_;
257 threadPool_ = 0;
258 if (reader_.is()) {
259 if (!isThread(reader_.get())) {
260 r = reader_;
262 reader_.clear();
264 if (writer_.is()) {
265 if (!isThread(writer_.get())) {
266 w = writer_;
268 writer_.clear();
270 state_ = STATE_FINAL;
272 assert(!(r.is() && w.is()));
273 if (r.is()) {
274 r->join();
275 } else if (w.is()) {
276 w->join();
278 if (tp != 0) {
279 uno_threadpool_destroy(tp);
282 return;
284 tp = threadPool_;
285 assert(!(final && isThread(reader_.get())));
286 if (!isThread(reader_.get())) {
287 std::swap(reader_, r);
289 w = writer_;
290 joinW = !isThread(writer_.get());
291 assert(!final || joinW);
292 if (joinW) {
293 writer_.clear();
295 ls.swap(listeners_);
296 state_ = final ? STATE_FINAL : STATE_TERMINATED;
298 try {
299 connection_->close();
300 } catch (const css::io::IOException & e) {
301 SAL_INFO("binaryurp", "caught IO exception '" << e.Message << '\'');
303 assert(w.is());
304 w->stop();
305 if (r.is()) {
306 r->join();
308 if (joinW) {
309 w->join();
311 assert(tp != 0);
312 uno_threadpool_dispose(tp);
313 Stubs s;
315 osl::MutexGuard g(mutex_);
316 s.swap(stubs_);
318 for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
319 for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j)
321 SAL_INFO(
322 "binaryurp",
323 "stub '" << i->first << "', '" << toString(j->first)
324 << "' still mapped at Bridge::terminate");
325 binaryUno_.get()->pExtEnv->revokeInterface(
326 binaryUno_.get()->pExtEnv, j->second.object.get());
329 factory_->removeBridge(this);
330 for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
331 try {
332 (*i)->disposing(
333 css::lang::EventObject(
334 static_cast< cppu::OWeakObject * >(this)));
335 } catch (const css::uno::RuntimeException & e) {
336 SAL_WARN(
337 "binaryurp",
338 "caught runtime exception '" << e.Message << '\'');
342 if (final) {
343 uno_threadpool_destroy(tp);
346 osl::MutexGuard g(mutex_);
347 if (final) {
348 threadPool_ = 0;
351 terminated_.set();
354 css::uno::Reference< css::connection::XConnection > Bridge::getConnection()
355 const
357 return connection_;
360 css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider()
361 const
363 return provider_;
366 css::uno::Mapping & Bridge::getCppToBinaryMapping() {
367 return cppToBinaryMapping_;
370 BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
371 css::uno::Any in(cppAny);
372 BinaryAny out;
373 out.~BinaryAny();
374 uno_copyAndConvertData(
375 out.get(), &in,
376 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
377 cppToBinaryMapping_.get());
378 return out;
381 uno_ThreadPool Bridge::getThreadPool() {
382 osl::MutexGuard g(mutex_);
383 checkDisposed();
384 assert(threadPool_ != 0);
385 return threadPool_;
388 rtl::Reference< Writer > Bridge::getWriter() {
389 osl::MutexGuard g(mutex_);
390 checkDisposed();
391 assert(writer_.is());
392 return writer_;
395 css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
396 OUString const & oid, css::uno::TypeDescription const & type)
398 assert(type.is());
399 if (oid.isEmpty()) {
400 return css::uno::UnoInterfaceReference();
402 css::uno::UnoInterfaceReference obj(findStub(oid, type));
403 if (!obj.is()) {
404 binaryUno_.get()->pExtEnv->getRegisteredInterface(
405 binaryUno_.get()->pExtEnv,
406 reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
407 reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
408 if (obj.is()) {
409 makeReleaseCall(oid, type);
410 } else {
411 obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
413 osl::MutexGuard g(mutex_);
414 assert(proxies_ < std::numeric_limits< std::size_t >::max());
415 ++proxies_;
417 binaryUno_.get()->pExtEnv->registerProxyInterface(
418 binaryUno_.get()->pExtEnv,
419 reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
420 oid.pData,
421 reinterpret_cast< typelib_InterfaceTypeDescription * >(
422 type.get()));
425 return obj;
428 OUString Bridge::registerOutgoingInterface(
429 css::uno::UnoInterfaceReference const & object,
430 css::uno::TypeDescription const & type)
432 assert(type.is());
433 if (!object.is()) {
434 return OUString();
436 OUString oid;
437 if (!Proxy::isProxy(this, object, &oid)) {
438 binaryUno_.get()->pExtEnv->getObjectIdentifier(
439 binaryUno_.get()->pExtEnv, &oid.pData, object.get());
440 osl::MutexGuard g(mutex_);
441 Stubs::iterator i(stubs_.find(oid));
442 Stub newStub;
443 Stub * stub = i == stubs_.end() ? &newStub : &i->second;
444 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 if (j == stub->end()) {
448 j = stub->insert(Stub::value_type(type, SubStub())).first;
449 if (stub == &newStub) {
450 i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
451 std::swap(i->second, newStub);
452 j = i->second.find(type);
453 assert(j != i->second.end());
455 j->second.object = object;
456 j->second.references = 1;
457 binaryUno_.get()->pExtEnv->registerInterface(
458 binaryUno_.get()->pExtEnv,
459 reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
460 oid.pData,
461 reinterpret_cast< typelib_InterfaceTypeDescription * >(
462 type.get()));
463 } else {
464 assert(stub != &newStub);
465 if (j->second.references == SAL_MAX_UINT32) {
466 throw css::uno::RuntimeException(
467 "URP: stub reference count overflow",
468 css::uno::Reference< css::uno::XInterface >());
470 ++j->second.references;
473 return oid;
476 css::uno::UnoInterfaceReference Bridge::findStub(
477 OUString const & oid, css::uno::TypeDescription const & type)
479 assert(!oid.isEmpty() && type.is());
480 osl::MutexGuard g(mutex_);
481 Stubs::iterator i(stubs_.find(oid));
482 if (i != stubs_.end()) {
483 Stub::iterator j(i->second.find(type));
484 if (j != i->second.end()) {
485 return j->second.object;
487 for (j = i->second.begin(); j != i->second.end(); ++j) {
488 if (typelib_typedescription_isAssignableFrom(
489 type.get(), j->first.get()))
491 return j->second.object;
495 return css::uno::UnoInterfaceReference();
498 void Bridge::releaseStub(
499 OUString const & oid, css::uno::TypeDescription const & type)
501 assert(!oid.isEmpty() && type.is());
502 css::uno::UnoInterfaceReference obj;
503 bool unused;
505 osl::MutexGuard g(mutex_);
506 Stubs::iterator i(stubs_.find(oid));
507 if (i == stubs_.end()) {
508 throw css::uno::RuntimeException(
509 "URP: release unknown stub",
510 css::uno::Reference< css::uno::XInterface >());
512 Stub::iterator j(i->second.find(type));
513 if (j == i->second.end()) {
514 throw css::uno::RuntimeException(
515 "URP: release unknown stub",
516 css::uno::Reference< css::uno::XInterface >());
518 assert(j->second.references > 0);
519 --j->second.references;
520 if (j->second.references == 0) {
521 obj = j->second.object;
522 i->second.erase(j);
523 if (i->second.empty()) {
524 stubs_.erase(i);
527 unused = becameUnused();
529 if (obj.is()) {
530 binaryUno_.get()->pExtEnv->revokeInterface(
531 binaryUno_.get()->pExtEnv, obj.get());
533 terminateWhenUnused(unused);
536 void Bridge::resurrectProxy(Proxy & proxy) {
537 uno_Interface * p = &proxy;
538 binaryUno_.get()->pExtEnv->registerProxyInterface(
539 binaryUno_.get()->pExtEnv,
540 reinterpret_cast< void ** >(&p), &freeProxyCallback,
541 proxy.getOid().pData,
542 reinterpret_cast< typelib_InterfaceTypeDescription * >(
543 proxy.getType().get()));
544 assert(p == &proxy);
547 void Bridge::revokeProxy(Proxy & proxy) {
548 binaryUno_.get()->pExtEnv->revokeInterface(
549 binaryUno_.get()->pExtEnv, &proxy);
552 void Bridge::freeProxy(Proxy & proxy) {
553 try {
554 makeReleaseCall(proxy.getOid(), proxy.getType());
555 } catch (const css::uno::RuntimeException & e) {
556 SAL_INFO(
557 "binaryurp", "caught runtime exception '" << e.Message << '\'');
558 } catch (const std::exception & e) {
559 SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
561 bool unused;
563 osl::MutexGuard g(mutex_);
564 assert(proxies_ > 0);
565 --proxies_;
566 unused = becameUnused();
568 terminateWhenUnused(unused);
571 void Bridge::incrementCalls(bool normalCall) throw () {
572 osl::MutexGuard g(mutex_);
573 assert(calls_ < std::numeric_limits< std::size_t >::max());
574 ++calls_;
575 normalCall_ |= normalCall;
578 void Bridge::decrementCalls() {
579 bool unused;
581 osl::MutexGuard g(mutex_);
582 assert(calls_ > 0);
583 --calls_;
584 unused = becameUnused();
586 terminateWhenUnused(unused);
589 void Bridge::incrementActiveCalls() throw () {
590 osl::MutexGuard g(mutex_);
591 assert(
592 activeCalls_ <= calls_ &&
593 activeCalls_ < std::numeric_limits< std::size_t >::max());
594 ++activeCalls_;
595 passive_.reset();
598 void Bridge::decrementActiveCalls() throw () {
599 osl::MutexGuard g(mutex_);
600 assert(activeCalls_ <= calls_ && activeCalls_ > 0);
601 --activeCalls_;
602 if (activeCalls_ == 0) {
603 passive_.set();
607 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)
612 std::auto_ptr< IncomingReply > resp;
614 uno_ThreadPool tp = getThreadPool();
615 AttachThread att(tp);
616 PopOutgoingRequest pop(
617 outgoingRequests_, att.getTid(),
618 OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
619 sendRequest(
620 att.getTid(), oid, css::uno::TypeDescription(), member,
621 inArguments);
622 pop.clear();
623 incrementCalls(true);
624 incrementActiveCalls();
625 void * job;
626 uno_threadpool_enter(tp, &job);
627 resp.reset(static_cast< IncomingReply * >(job));
628 decrementActiveCalls();
629 decrementCalls();
631 if (resp.get() == 0) {
632 throw css::lang::DisposedException(
633 "Binary URP bridge disposed during call",
634 static_cast< cppu::OWeakObject * >(this));
636 *returnValue = resp->returnValue;
637 if (!resp->exception) {
638 *outArguments = resp->outArguments;
640 return resp->exception;
643 void Bridge::sendRequestChangeRequest() {
644 assert(mode_ == MODE_REQUESTED);
645 random_ = random();
646 std::vector< BinaryAny > a;
647 a.push_back(
648 BinaryAny(
649 css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
650 &random_));
651 sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
654 void Bridge::handleRequestChangeReply(
655 bool exception, BinaryAny const & returnValue)
657 try {
658 throwException(exception, returnValue);
659 } 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 if (mode_ != MODE_REQUESTED) {
664 throw;
666 SAL_WARN(
667 "binaryurp",
668 "requestChange caught RuntimeException \'" << e.Message
669 << "' in state 'requested'");
670 mode_ = MODE_NORMAL;
671 getWriter()->unblock();
672 decrementCalls();
673 return;
675 sal_Int32 n = *static_cast< sal_Int32 * >(
676 returnValue.getValue(
677 css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
678 sal_Int32 exp = 0;
679 switch (mode_) {
680 case MODE_REQUESTED:
681 case MODE_REPLY_1:
682 exp = 1;
683 break;
684 case MODE_REPLY_MINUS1:
685 exp = -1;
686 mode_ = MODE_REQUESTED;
687 break;
688 case MODE_REPLY_0:
689 exp = 0;
690 mode_ = MODE_WAIT;
691 break;
692 default:
693 assert(false); // this cannot happen
694 break;
696 if (n != exp) {
697 throw css::uno::RuntimeException(
698 "URP: requestChange reply with unexpected return value received",
699 static_cast< cppu::OWeakObject * >(this));
701 decrementCalls();
702 switch (exp) {
703 case -1:
704 sendRequestChangeRequest();
705 break;
706 case 0:
707 break;
708 case 1:
709 sendCommitChangeRequest();
710 break;
711 default:
712 assert(false); // this cannot happen
713 break;
717 void Bridge::handleCommitChangeReply(
718 bool exception, BinaryAny const & returnValue)
720 bool ccMode = true;
721 try {
722 throwException(exception, returnValue);
723 } catch (const css::bridge::InvalidProtocolChangeException &) {
724 ccMode = false;
726 if (ccMode) {
727 setCurrentContextMode();
729 assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
730 mode_ = MODE_NORMAL;
731 getWriter()->unblock();
732 decrementCalls();
735 void Bridge::handleRequestChangeRequest(
736 rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
738 assert(inArguments.size() == 1);
739 switch (mode_) {
740 case MODE_REQUESTED:
742 sal_Int32 n2 = *static_cast< sal_Int32 * >(
743 inArguments[0].getValue(
744 css::uno::TypeDescription(
745 cppu::UnoType< sal_Int32 >::get())));
746 sal_Int32 ret;
747 if (n2 > random_) {
748 ret = 1;
749 mode_ = MODE_REPLY_0;
750 } else if (n2 == random_) {
751 ret = -1;
752 mode_ = MODE_REPLY_MINUS1;
753 } else {
754 ret = 0;
755 mode_ = MODE_REPLY_1;
757 getWriter()->sendDirectReply(
758 tid, protPropRequest_, false,
759 BinaryAny(
760 css::uno::TypeDescription(
761 cppu::UnoType< sal_Int32 >::get()),
762 &ret),
763 std::vector< BinaryAny >());
764 break;
766 case MODE_NORMAL:
768 mode_ = MODE_NORMAL_WAIT;
769 sal_Int32 ret = 1;
770 getWriter()->queueReply(
771 tid, protPropRequest_, false, false,
772 BinaryAny(
773 css::uno::TypeDescription(
774 cppu::UnoType< sal_Int32 >::get()),
775 &ret),
776 std::vector< BinaryAny >(), false);
777 break;
779 default:
780 throw css::uno::RuntimeException(
781 "URP: unexpected requestChange request received",
782 static_cast< cppu::OWeakObject * >(this));
786 void Bridge::handleCommitChangeRequest(
787 rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
789 bool ccMode = false;
790 bool exc = false;
791 BinaryAny ret;
792 assert(inArguments.size() == 1);
793 css::uno::Sequence< css::bridge::ProtocolProperty > s;
794 bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
795 assert(ok);
796 (void) ok; // avoid warnings
797 for (sal_Int32 i = 0; i != s.getLength(); ++i) {
798 if (s[i].Name == "CurrentContext") {
799 ccMode = true;
800 } else {
801 ccMode = false;
802 exc = true;
803 ret = mapCppToBinaryAny(
804 css::uno::makeAny(
805 css::bridge::InvalidProtocolChangeException(
806 "InvalidProtocolChangeException",
807 css::uno::Reference< css::uno::XInterface >(), s[i],
808 1)));
809 break;
812 switch (mode_) {
813 case MODE_WAIT:
814 getWriter()->sendDirectReply(
815 tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
816 if (ccMode) {
817 setCurrentContextMode();
818 mode_ = MODE_NORMAL;
819 getWriter()->unblock();
820 } else {
821 mode_ = MODE_REQUESTED;
822 sendRequestChangeRequest();
824 break;
825 case MODE_NORMAL_WAIT:
826 getWriter()->queueReply(
827 tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(),
828 ccMode);
829 mode_ = MODE_NORMAL;
830 break;
831 default:
832 throw css::uno::RuntimeException(
833 "URP: unexpected commitChange request received",
834 static_cast< cppu::OWeakObject * >(this));
838 OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
839 OutgoingRequest req(outgoingRequests_.top(tid));
840 outgoingRequests_.pop(tid);
841 return req;
844 bool Bridge::isProtocolPropertiesRequest(
845 OUString const & oid, css::uno::TypeDescription const & type) const
847 return oid == protPropOid_ && type.equals(protPropType_);
850 void Bridge::setCurrentContextMode() {
851 osl::MutexGuard g(mutex_);
852 currentContextMode_ = true;
855 bool Bridge::isCurrentContextMode() {
856 osl::MutexGuard g(mutex_);
857 return currentContextMode_;
860 Bridge::~Bridge() {
861 #if OSL_DEBUG_LEVEL > 0
863 osl::MutexGuard g(mutex_);
864 SAL_WARN_IF(
865 state_ == STATE_STARTED || state_ == STATE_TERMINATED, "binaryurp",
866 "undisposed bridge, potential deadlock ahead");
868 #endif
869 dispose();
872 css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
873 OUString const & sInstanceName) throw (css::uno::RuntimeException)
875 if (sInstanceName.isEmpty()) {
876 throw css::uno::RuntimeException(
877 "XBridge::getInstance sInstanceName must be non-empty",
878 static_cast< cppu::OWeakObject * >(this));
880 for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
881 if (sInstanceName[i] > 0x7F) {
882 throw css::io::IOException(
883 ("XBridge::getInstance sInstanceName contains non-ASCII"
884 " character"),
885 css::uno::Reference< css::uno::XInterface >());
888 css::uno::TypeDescription ifc(
889 cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get());
890 typelib_TypeDescription * p = ifc.get();
891 std::vector< BinaryAny > inArgs;
892 inArgs.push_back(
893 BinaryAny(
894 css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
895 &p));
896 BinaryAny ret;
897 std::vector< BinaryAny> outArgs;
898 bool exc = makeCall(
899 sInstanceName,
900 css::uno::TypeDescription(
901 "com.sun.star.uno.XInterface::queryInterface"),
902 false, inArgs, &ret, &outArgs);
903 throwException(exc, ret);
904 return css::uno::Reference< css::uno::XInterface >(
905 static_cast< css::uno::XInterface * >(
906 binaryToCppMapping_.mapInterface(
907 *static_cast< uno_Interface ** >(ret.getValue(ifc)),
908 ifc.get())),
909 css::uno::UNO_REF_NO_ACQUIRE);
912 OUString Bridge::getName() throw (css::uno::RuntimeException) {
913 return name_;
916 OUString Bridge::getDescription() throw (css::uno::RuntimeException) {
917 OUStringBuffer b(name_);
918 b.append(sal_Unicode(':'));
919 b.append(connection_->getDescription());
920 return b.makeStringAndClear();
923 void Bridge::dispose() throw (css::uno::RuntimeException) {
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 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 passive_.wait();
936 void Bridge::addEventListener(
937 css::uno::Reference< css::lang::XEventListener > const & xListener)
938 throw (css::uno::RuntimeException)
940 assert(xListener.is());
942 osl::MutexGuard g(mutex_);
943 assert(state_ != STATE_INITIAL);
944 if (state_ == STATE_STARTED) {
945 listeners_.push_back(xListener);
946 return;
949 xListener->disposing(
950 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
953 void Bridge::removeEventListener(
954 css::uno::Reference< css::lang::XEventListener > const & aListener)
955 throw (css::uno::RuntimeException)
957 osl::MutexGuard g(mutex_);
958 Listeners::iterator i(
959 std::find(listeners_.begin(), listeners_.end(), aListener));
960 if (i != listeners_.end()) {
961 listeners_.erase(i);
965 void Bridge::sendCommitChangeRequest() {
966 assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
967 css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
968 s[0].Name = "CurrentContext";
969 std::vector< BinaryAny > a;
970 a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
971 sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
974 void Bridge::sendProtPropRequest(
975 OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments)
977 assert(
978 kind == OutgoingRequest::KIND_REQUEST_CHANGE ||
979 kind == OutgoingRequest::KIND_COMMIT_CHANGE);
980 incrementCalls(false);
981 css::uno::TypeDescription member(
982 kind == OutgoingRequest::KIND_REQUEST_CHANGE
983 ? protPropRequest_ : protPropCommit_);
984 PopOutgoingRequest pop(
985 outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
986 getWriter()->sendDirectRequest(
987 protPropTid_, protPropOid_, protPropType_, member, inArguments);
988 pop.clear();
991 void Bridge::makeReleaseCall(
992 OUString const & oid, css::uno::TypeDescription const & type)
994 AttachThread att(getThreadPool());
995 sendRequest(
996 att.getTid(), oid, type,
997 css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
998 std::vector< BinaryAny >());
1001 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)
1007 getWriter()->queueRequest(tid, oid, type, member, inArguments);
1010 void Bridge::throwException(bool exception, BinaryAny const & value) {
1011 if (exception) {
1012 cppu::throwException(mapBinaryToCppAny(value));
1016 css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
1017 BinaryAny in(binaryAny);
1018 css::uno::Any out;
1019 out.~Any();
1020 uno_copyAndConvertData(
1021 &out, in.get(),
1022 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
1023 binaryToCppMapping_.get());
1024 return out;
1027 bool Bridge::becameUnused() const {
1028 return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
1031 void Bridge::terminateWhenUnused(bool unused) {
1032 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 terminate(false);
1040 void Bridge::checkDisposed() {
1041 assert(state_ != STATE_INITIAL);
1042 if (state_ != STATE_STARTED) {
1043 throw css::lang::DisposedException(
1044 "Binary URP bridge already disposed",
1045 static_cast< cppu::OWeakObject * >(this));
1051 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */