LibreOffice Module binaryurp (master) 1
bridge.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
22#include <algorithm>
23#include <cassert>
24#include <cstddef>
25#include <limits>
26#include <memory>
27#include <utility>
28#include <vector>
29
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>
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/string.h>
51#include <rtl/ustring.hxx>
52#include <sal/log.hxx>
53#include <sal/types.h>
54#include <typelib/typeclass.h>
55#include <typelib/typedescription.h>
56#include <typelib/typedescription.hxx>
57#include <uno/dispatcher.hxx>
58#include <uno/environment.hxx>
59#include <uno/lbnames.h>
60
61#include "binaryany.hxx"
62#include "bridge.hxx"
63#include "bridgefactory.hxx"
64#include "incomingreply.hxx"
65#include "lessoperators.hxx"
66#include "outgoingrequest.hxx"
67#include "outgoingrequests.hxx"
68#include "proxy.hxx"
69#include "reader.hxx"
70
71namespace binaryurp {
72
73namespace {
74
75sal_Int32 random() {
76 sal_Int32 n;
77 rtlRandomPool pool = rtl_random_createPool();
78 rtl_random_getBytes(pool, &n, sizeof n);
79 rtl_random_destroyPool(pool);
80 return n;
81}
82
83OUString toString(css::uno::TypeDescription const & type) {
85 assert(d != nullptr && d->pTypeName != nullptr);
86 return OUString(d->pTypeName);
87}
88
89extern "C" void freeProxyCallback(
90 SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pProxy)
91{
92 assert(pProxy != nullptr);
93 static_cast< Proxy * >(pProxy)->do_free();
94}
95
96bool isThread(salhelper::Thread * thread) {
97 assert(thread != nullptr);
98 return osl::Thread::getCurrentIdentifier() == thread->getIdentifier();
99}
100
101class AttachThread {
102public:
103 explicit AttachThread(uno_ThreadPool threadPool);
104
105 ~AttachThread();
106
107 const rtl::ByteSequence& getTid() const noexcept { return tid_;}
108
109private:
110 AttachThread(const AttachThread&) = delete;
111 AttachThread& operator=(const AttachThread&) = delete;
112
113 uno_ThreadPool threadPool_;
114 rtl::ByteSequence tid_;
115};
116
117AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
118 sal_Sequence * s = nullptr;
120 tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
122}
123
124AttachThread::~AttachThread() {
127}
128
129
130class PopOutgoingRequest {
131public:
132 PopOutgoingRequest(
133 OutgoingRequests & requests, rtl::ByteSequence tid,
134 OutgoingRequest const & request);
135
136 ~PopOutgoingRequest();
137
138 void clear();
139
140private:
141 PopOutgoingRequest(const PopOutgoingRequest&) = delete;
142 PopOutgoingRequest& operator=(const PopOutgoingRequest&) = delete;
143
144 OutgoingRequests & requests_;
145 rtl::ByteSequence tid_;
147};
148
149PopOutgoingRequest::PopOutgoingRequest(
150 OutgoingRequests & requests, rtl::ByteSequence tid,
151 OutgoingRequest const & request):
152 requests_(requests), tid_(std::move(tid)), cleared_(false)
153{
154 requests_.push(tid_, request);
155}
156
157PopOutgoingRequest::~PopOutgoingRequest() {
158 if (!cleared_) {
159 requests_.pop(tid_);
160 }
161}
162
163void PopOutgoingRequest::clear() {
164 cleared_ = true;
165}
166
167}
168
170 com::sun::star::uno::UnoInterfaceReference object;
171
172 sal_uInt32 references;
173};
174
175Bridge::Bridge(
176 rtl::Reference< BridgeFactory > const & factory, OUString name,
177 css::uno::Reference< css::connection::XConnection > const & connection,
178 css::uno::Reference< css::bridge::XInstanceProvider > provider):
179 factory_(factory), name_(std::move(name)), connection_(connection),
180 provider_(std::move(provider)),
181 binaryUno_(UNO_LB_UNO),
182 cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO),
183 binaryToCppMapping_(UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME),
184 protPropTid_(
185 reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"),
186 RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
187 protPropOid_("UrpProtocolProperties"),
188 protPropType_(
189 cppu::UnoType<
190 css::uno::Reference< css::bridge::XProtocolProperties > >::get()),
191 protPropRequest_("com.sun.star.bridge.XProtocolProperties::requestChange"),
192 protPropCommit_("com.sun.star.bridge.XProtocolProperties::commitChange"),
193 state_(STATE_INITIAL), threadPool_(nullptr), currentContextMode_(false),
194 proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
195 mode_(MODE_REQUESTED)
196{
197 assert(factory.is() && connection.is());
198 if (!binaryUno_.is()) {
199 throw css::uno::RuntimeException("URP: no binary UNO environment");
200 }
201 if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) {
202 throw css::uno::RuntimeException("URP: no C++ UNO mapping");
203 }
204 passive_.set();
205 // coverity[uninit_member] - random_ is set in due course by the reader_ thread's state machine
206}
207
209 rtl::Reference r(new Reader(this));
210 rtl::Reference w(new Writer(this));
211 {
212 std::lock_guard g(mutex_);
213 assert(
214 state_ == STATE_INITIAL && threadPool_ == nullptr && !writer_.is() &&
215 !reader_.is());
217 assert(threadPool_ != nullptr);
218 reader_ = r;
219 writer_ = w;
221 }
222 // It is important to call reader_->launch() last here; both
223 // Writer::execute and Reader::execute can call Bridge::terminate, but
224 // Writer::execute is initially blocked in unblocked_.wait() until
225 // Reader::execute has called bridge_->sendRequestChangeRequest(), so
226 // effectively only reader_->launch() can lead to an early call to
227 // Bridge::terminate
228 w->launch();
229 r->launch();
230}
231
232void Bridge::terminate(bool final) {
233 uno_ThreadPool tp;
234 // Make sure function-local variables (Stubs s, etc.) are destroyed before
235 // the final uno_threadpool_destroy/threadPool_ = 0:
236 {
239 bool joinW;
240 Listeners ls;
241 {
242 std::unique_lock g(mutex_);
243 switch (state_) {
244 case STATE_INITIAL: // via ~Bridge -> dispose -> terminate
245 case STATE_FINAL:
246 return;
247 case STATE_STARTED:
248 break;
249 case STATE_TERMINATED:
250 if (final) {
251 g.unlock();
252 terminated_.wait();
253 {
254 std::lock_guard g2(mutex_);
255 tp = threadPool_;
256 threadPool_ = nullptr;
257 if (reader_.is()) {
258 if (!isThread(reader_.get())) {
259 r = reader_;
260 }
261 reader_.clear();
262 }
263 if (writer_.is()) {
264 if (!isThread(writer_.get())) {
265 w = writer_;
266 }
267 writer_.clear();
268 }
270 }
271 assert(!(r.is() && w.is()));
272 if (r.is()) {
273 r->join();
274 } else if (w.is()) {
275 w->join();
276 }
277 if (tp != nullptr) {
279 }
280 }
281 return;
282 }
283 tp = threadPool_;
284 assert(!(final && isThread(reader_.get())));
285 if (!isThread(reader_.get())) {
286 std::swap(reader_, r);
287 }
288 w = writer_;
289 joinW = !isThread(writer_.get());
290 assert(!final || joinW);
291 if (joinW) {
292 writer_.clear();
293 }
294 ls.swap(listeners_);
296 }
297 try {
298 connection_->close();
299 } catch (const css::io::IOException & e) {
300 SAL_INFO("binaryurp", "caught IO exception '" << e << '\'');
301 }
302 assert(w.is());
303 w->stop();
304 if (r.is()) {
305 r->join();
306 }
307 if (joinW) {
308 w->join();
309 }
310 assert(tp != nullptr);
312 Stubs s;
313 {
314 std::lock_guard g(mutex_);
315 s.swap(stubs_);
316 }
317 for (auto & stub : s)
318 {
319 for (auto & item : stub.second)
320 {
321 SAL_INFO(
322 "binaryurp",
323 "stub '" << stub.first << "', '" << toString(item.first)
324 << "' still mapped at Bridge::terminate");
325 binaryUno_.get()->pExtEnv->revokeInterface(
326 binaryUno_.get()->pExtEnv, item.second.object.get());
327 }
328 }
329 factory_->removeBridge(this);
330 for (auto const& listener : ls)
331 {
332 try {
333 listener->disposing(
334 css::lang::EventObject(
335 getXWeak()));
336 } catch (const css::uno::RuntimeException & e) {
337 SAL_WARN("binaryurp", "caught " << e);
338 }
339 }
340 }
341 if (final) {
343 }
344 {
345 std::lock_guard g(mutex_);
346 if (final) {
347 threadPool_ = nullptr;
348 }
349 }
350 terminated_.set();
351}
352
353
354BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
355 css::uno::Any in(cppAny);
356 BinaryAny out;
357 out.~BinaryAny();
359 &out.get(), &in,
360 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
361 cppToBinaryMapping_.get());
362 return out;
363}
364
365uno_ThreadPool Bridge::getThreadPool() {
366 std::lock_guard g(mutex_);
368 assert(threadPool_ != nullptr);
369 return threadPool_;
370}
371
373 std::lock_guard g(mutex_);
375 assert(writer_.is());
376 return writer_;
377}
378
379css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
380 OUString const & oid, css::uno::TypeDescription const & type)
381{
382 assert(type.is());
383 if (oid.isEmpty()) {
384 return css::uno::UnoInterfaceReference();
385 }
386 css::uno::UnoInterfaceReference obj(findStub(oid, type));
387 if (!obj.is()) {
388 binaryUno_.get()->pExtEnv->getRegisteredInterface(
389 binaryUno_.get()->pExtEnv,
390 reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
391 reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
392 if (obj.is()) {
393 makeReleaseCall(oid, type);
394 } else {
395 obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
396 {
397 std::lock_guard g(mutex_);
398 assert(proxies_ < std::numeric_limits< std::size_t >::max());
399 ++proxies_;
400 }
401 binaryUno_.get()->pExtEnv->registerProxyInterface(
402 binaryUno_.get()->pExtEnv,
403 reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
404 oid.pData,
405 reinterpret_cast< typelib_InterfaceTypeDescription * >(
406 type.get()));
407 }
408 }
409 return obj;
410}
411
413 css::uno::UnoInterfaceReference const & object,
414 css::uno::TypeDescription const & type)
415{
416 assert(type.is());
417 if (!object.is()) {
418 return OUString();
419 }
420 OUString oid;
421 if (!Proxy::isProxy(this, object, &oid)) {
422 binaryUno_.get()->pExtEnv->getObjectIdentifier(
423 binaryUno_.get()->pExtEnv, &oid.pData, object.get());
424 std::lock_guard g(mutex_);
425 Stubs::iterator i(stubs_.find(oid));
426 Stub newStub;
427 Stub * stub = i == stubs_.end() ? &newStub : &i->second;
428 Stub::iterator j(stub->find(type));
429 //TODO: Release sub-stub if it is not successfully sent to remote side
430 // (otherwise, stub will leak until terminate()):
431 if (j == stub->end()) {
432 j = stub->emplace(type, SubStub()).first;
433 if (stub == &newStub) {
434 i = stubs_.emplace(oid, Stub()).first;
435 std::swap(i->second, newStub);
436 j = i->second.find(type);
437 assert(j != i->second.end());
438 }
439 j->second.object = object;
440 j->second.references = 1;
441 binaryUno_.get()->pExtEnv->registerInterface(
442 binaryUno_.get()->pExtEnv,
443 reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
444 oid.pData,
445 reinterpret_cast< typelib_InterfaceTypeDescription * >(
446 type.get()));
447 } else {
448 assert(stub != &newStub);
449 if (j->second.references == SAL_MAX_UINT32) {
450 throw css::uno::RuntimeException(
451 "URP: stub reference count overflow");
452 }
453 ++j->second.references;
454 }
455 }
456 return oid;
457}
458
459css::uno::UnoInterfaceReference Bridge::findStub(
460 OUString const & oid, css::uno::TypeDescription const & type)
461{
462 assert(!oid.isEmpty() && type.is());
463 std::lock_guard g(mutex_);
464 Stubs::iterator i(stubs_.find(oid));
465 if (i != stubs_.end()) {
466 Stub::iterator j(i->second.find(type));
467 if (j != i->second.end()) {
468 return j->second.object;
469 }
470 for (auto const& item : i->second)
471 {
473 type.get(), item.first.get()))
474 {
475 return item.second.object;
476 }
477 }
478 }
479 return css::uno::UnoInterfaceReference();
480}
481
483 OUString const & oid, css::uno::TypeDescription const & type)
484{
485 assert(!oid.isEmpty() && type.is());
486 css::uno::UnoInterfaceReference obj;
487 bool unused;
488 {
489 std::lock_guard g(mutex_);
490 Stubs::iterator i(stubs_.find(oid));
491 if (i == stubs_.end()) {
492 throw css::uno::RuntimeException("URP: release unknown stub");
493 }
494 Stub::iterator j(i->second.find(type));
495 if (j == i->second.end()) {
496 throw css::uno::RuntimeException("URP: release unknown stub");
497 }
498 assert(j->second.references > 0);
499 --j->second.references;
500 if (j->second.references == 0) {
501 obj = j->second.object;
502 i->second.erase(j);
503 if (i->second.empty()) {
504 stubs_.erase(i);
505 }
506 }
507 unused = becameUnused();
508 }
509 if (obj.is()) {
510 binaryUno_.get()->pExtEnv->revokeInterface(
511 binaryUno_.get()->pExtEnv, obj.get());
512 }
513 terminateWhenUnused(unused);
514}
515
517 uno_Interface * p = &proxy;
518 binaryUno_.get()->pExtEnv->registerProxyInterface(
519 binaryUno_.get()->pExtEnv,
520 reinterpret_cast< void ** >(&p), &freeProxyCallback,
521 proxy.getOid().pData,
522 reinterpret_cast< typelib_InterfaceTypeDescription * >(
523 proxy.getType().get()));
524 assert(p == &proxy);
525}
526
528 binaryUno_.get()->pExtEnv->revokeInterface(
529 binaryUno_.get()->pExtEnv, &proxy);
530}
531
533 try {
534 makeReleaseCall(proxy.getOid(), proxy.getType());
535 } catch (const css::uno::RuntimeException & e) {
536 SAL_INFO(
537 "binaryurp", "caught runtime exception '" << e << '\'');
538 } catch (const std::exception & e) {
539 SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
540 }
541 bool unused;
542 {
543 std::lock_guard g(mutex_);
544 assert(proxies_ > 0);
545 --proxies_;
546 unused = becameUnused();
547 }
548 terminateWhenUnused(unused);
549}
550
551void Bridge::incrementCalls(bool normalCall) noexcept {
552 std::lock_guard g(mutex_);
553 assert(calls_ < std::numeric_limits< std::size_t >::max());
554 ++calls_;
555 normalCall_ |= normalCall;
556}
557
559 bool unused;
560 {
561 std::lock_guard g(mutex_);
562 assert(calls_ > 0);
563 --calls_;
564 unused = becameUnused();
565 }
566 terminateWhenUnused(unused);
567}
568
570 std::lock_guard g(mutex_);
571 assert(
572 activeCalls_ <= calls_ &&
573 activeCalls_ < std::numeric_limits< std::size_t >::max());
574 ++activeCalls_;
575 passive_.reset();
576}
577
579 std::lock_guard g(mutex_);
580 assert(activeCalls_ <= calls_ && activeCalls_ > 0);
581 --activeCalls_;
582 if (activeCalls_ == 0) {
583 passive_.set();
584 }
585}
586
588 OUString const & oid, css::uno::TypeDescription const & member,
589 bool setter, std::vector< BinaryAny >&& inArguments,
590 BinaryAny * returnValue, std::vector< BinaryAny > * outArguments)
591{
592 std::unique_ptr< IncomingReply > resp;
593 {
594 uno_ThreadPool tp = getThreadPool();
595 AttachThread att(tp);
596 PopOutgoingRequest pop(
597 outgoingRequests_, att.getTid(),
600 att.getTid(), oid, css::uno::TypeDescription(), member,
601 std::move(inArguments));
602 pop.clear();
603 incrementCalls(true);
605 void * job;
606 uno_threadpool_enter(tp, &job);
607 resp.reset(static_cast< IncomingReply * >(job));
610 }
611 if (resp == nullptr)
612 {
613 throw css::lang::DisposedException(
614 "Binary URP bridge disposed during call",
615 getXWeak());
616 }
617 *returnValue = resp->returnValue;
618 if (!resp->exception) {
619 *outArguments = resp->outArguments;
620 }
621 return resp->exception;
622}
623
625 assert(mode_ == MODE_REQUESTED);
626 random_ = random();
627 std::vector< BinaryAny > a;
628 a.emplace_back(
629 css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
630 &random_);
632}
633
635 bool exception, BinaryAny const & returnValue)
636{
637 try {
638 throwException(exception, returnValue);
639 } catch (css::uno::RuntimeException & e) {
640 // Before OOo 2.2, Java URP would throw a RuntimeException when
641 // receiving a requestChange message (see i#35277 "Java URP: Support
642 // Manipulation of Protocol Properties"):
643 if (mode_ != MODE_REQUESTED) {
644 throw;
645 }
646 SAL_WARN(
647 "binaryurp",
648 "requestChange caught " << e << " in state 'requested'");
650 getWriter()->unblock();
652 return;
653 }
654 sal_Int32 n = *static_cast< sal_Int32 * >(
655 returnValue.getValue(
656 css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
657 sal_Int32 exp = 0;
658 switch (mode_) {
659 case MODE_REQUESTED:
660 case MODE_REPLY_1:
661 exp = 1;
662 break;
664 exp = -1;
666 break;
667 case MODE_REPLY_0:
668 exp = 0;
670 break;
671 default:
672 assert(false); // this cannot happen
673 break;
674 }
675 if (n != exp) {
676 throw css::uno::RuntimeException(
677 "URP: requestChange reply with unexpected return value received",
678 getXWeak());
679 }
681 switch (exp) {
682 case -1:
684 break;
685 case 0:
686 break;
687 case 1:
689 break;
690 default:
691 assert(false); // this cannot happen
692 break;
693 }
694}
695
697 bool exception, BinaryAny const & returnValue)
698{
699 bool bCcMode = true;
700 try {
701 throwException(exception, returnValue);
702 } catch (const css::bridge::InvalidProtocolChangeException &) {
703 bCcMode = false;
704 }
705 if (bCcMode) {
707 }
708 assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
710 getWriter()->unblock();
712}
713
715 rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
716{
717 assert(inArguments.size() == 1);
718 switch (mode_) {
719 case MODE_REQUESTED:
720 {
721 sal_Int32 n2 = *static_cast< sal_Int32 * >(
722 inArguments[0].getValue(
723 css::uno::TypeDescription(
725 sal_Int32 ret;
726 if (n2 > random_) {
727 ret = 1;
729 } else if (n2 == random_) {
730 ret = -1;
732 } else {
733 ret = 0;
735 }
736 getWriter()->sendDirectReply(
737 tid, protPropRequest_, false,
738 BinaryAny(
739 css::uno::TypeDescription(
741 &ret),
742 std::vector< BinaryAny >());
743 break;
744 }
745 case MODE_NORMAL:
746 {
748 sal_Int32 ret = 1;
749 getWriter()->queueReply(
750 tid, protPropRequest_, false, false,
751 BinaryAny(
752 css::uno::TypeDescription(
754 &ret),
755 std::vector< BinaryAny >(), false);
756 break;
757 }
758 default:
759 throw css::uno::RuntimeException(
760 "URP: unexpected requestChange request received",
761 getXWeak());
762 }
763}
764
766 rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
767{
768 bool bCcMode = false;
769 bool bExc = false;
770 BinaryAny ret;
771 assert(inArguments.size() == 1);
772 css::uno::Sequence< css::bridge::ProtocolProperty > s;
773 [[maybe_unused]] bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
774 assert(ok);
775 for (const auto & pp : std::as_const(s)) {
776 if (pp.Name == "CurrentContext") {
777 bCcMode = true;
778 } else {
779 bCcMode = false;
780 bExc = true;
781 ret = mapCppToBinaryAny(
782 css::uno::Any(
783 css::bridge::InvalidProtocolChangeException(
784 "InvalidProtocolChangeException",
785 css::uno::Reference< css::uno::XInterface >(), pp,
786 1)));
787 break;
788 }
789 }
790 switch (mode_) {
791 case MODE_WAIT:
792 getWriter()->sendDirectReply(
793 tid, protPropCommit_, bExc, ret, std::vector< BinaryAny >());
794 if (bCcMode) {
797 getWriter()->unblock();
798 } else {
801 }
802 break;
803 case MODE_NORMAL_WAIT:
804 getWriter()->queueReply(
805 tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(),
806 bCcMode);
808 break;
809 default:
810 throw css::uno::RuntimeException(
811 "URP: unexpected commitChange request received",
812 getXWeak());
813 }
814}
815
816OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
819 return req;
820}
821
823 std::u16string_view oid, css::uno::TypeDescription const & type) const
824{
825 return oid == protPropOid_ && type.equals(protPropType_);
826}
827
829 std::lock_guard g(mutex_);
830 currentContextMode_ = true;
831}
832
834 std::lock_guard g(mutex_);
835 return currentContextMode_;
836}
837
839#if OSL_DEBUG_LEVEL > 0
840 {
841 std::lock_guard g(mutex_);
843 state_ == STATE_STARTED || state_ == STATE_TERMINATED, "binaryurp",
844 "undisposed bridge \"" << name_ <<"\" in state " << state_
845 << ", potential deadlock ahead");
846 }
847#endif
848 dispose();
849}
850
851css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
852 OUString const & sInstanceName)
853{
854 if (sInstanceName.isEmpty()) {
855 throw css::uno::RuntimeException(
856 "XBridge::getInstance sInstanceName must be non-empty",
857 getXWeak());
858 }
859 for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
860 if (sInstanceName[i] > 0x7F) {
861 throw css::uno::RuntimeException(
862 "XBridge::getInstance sInstanceName contains non-ASCII"
863 " character");
864 }
865 }
866 css::uno::TypeDescription ifc(cppu::UnoType<css::uno::XInterface>::get());
867 typelib_TypeDescription * p = ifc.get();
868 std::vector< BinaryAny > inArgs;
869 inArgs.emplace_back(
870 css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
871 &p);
872 BinaryAny ret;
873 std::vector< BinaryAny> outArgs;
874 bool bExc = makeCall(
875 sInstanceName,
876 css::uno::TypeDescription(
877 "com.sun.star.uno.XInterface::queryInterface"),
878 false, std::move(inArgs), &ret, &outArgs);
879 throwException(bExc, ret);
880 auto const t = ret.getType();
881 if (t.get()->eTypeClass == typelib_TypeClass_VOID) {
882 return {};
883 }
884 if (!t.equals(ifc)) {
885 throw css::uno::RuntimeException(
886 "initial object queryInterface for OID \"" + sInstanceName + "\" returned ANY of type "
887 + OUString::unacquired(&t.get()->pTypeName));
888 }
889 auto const val = *static_cast< uno_Interface ** >(ret.getValue(ifc));
890 if (val == nullptr) {
891 throw css::uno::RuntimeException(
892 "initial object queryInterface for OID \"" + sInstanceName
893 + "\" returned null css.uno.XInterface ANY");
894 }
895 return css::uno::Reference< css::uno::XInterface >(
896 static_cast< css::uno::XInterface * >(
897 binaryToCppMapping_.mapInterface(
898 val,
899 ifc.get())),
900 SAL_NO_ACQUIRE);
901}
902
903OUString Bridge::getName() {
904 return name_;
905}
906
908 OUString b = name_ + ":" + connection_->getDescription();
909 return b;
910}
911
913 // For terminate(true) not to deadlock, an external protocol must ensure
914 // that dispose is not called from a thread pool worker thread (that dispose
915 // is never called from the reader or writer thread is already ensured
916 // internally):
917 terminate(true);
918 // OOo expects dispose to not return while there are still remote calls in
919 // progress; an external protocol must ensure that dispose is not called
920 // from within an incoming or outgoing remote call, as passive_.wait() would
921 // otherwise deadlock:
922 passive_.wait();
923}
924
926 css::uno::Reference< css::lang::XEventListener > const & xListener)
927{
928 assert(xListener.is());
929 {
930 std::lock_guard g(mutex_);
931 assert(state_ != STATE_INITIAL);
932 if (state_ == STATE_STARTED) {
933 listeners_.push_back(xListener);
934 return;
935 }
936 }
937 xListener->disposing(
938 css::lang::EventObject(getXWeak()));
939}
940
942 css::uno::Reference< css::lang::XEventListener > const & aListener)
943{
944 std::lock_guard g(mutex_);
945 Listeners::iterator i(
946 std::find(listeners_.begin(), listeners_.end(), aListener));
947 if (i != listeners_.end()) {
948 listeners_.erase(i);
949 }
950}
951
953 assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
954 css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
955 s.getArray()[0].Name = "CurrentContext";
956 std::vector< BinaryAny > a { mapCppToBinaryAny(css::uno::Any(s)) };
958}
959
961 OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments)
962{
963 assert(
966 incrementCalls(false);
967 css::uno::TypeDescription member(
970 PopOutgoingRequest pop(
971 outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
972 getWriter()->sendDirectRequest(
973 protPropTid_, protPropOid_, protPropType_, member, inArguments);
974 pop.clear();
975}
976
978 OUString const & oid, css::uno::TypeDescription const & type)
979{
980 //HACK to decouple the processing of release calls from all other threads. Normally, sending
981 // the release request should use the current thread's TID (via AttachThread), which would cause
982 // that asynchronous request to be processed by a physical thread that is paired with the
983 // physical thread processing the normal synchronous call stack (see ThreadIdHashMap in
984 // cppu/source/threadpool/threadpool.hxx). However, that can lead to deadlock when a thread
985 // illegally makes a synchronous UNO call with the SolarMutex locked (e.g.,
986 // SfxBaseModel::postEvent_Impl in sfx2/source/doc/sfxbasemodel.cxx doing documentEventOccurred
987 // and notifyEvent calls), and while that call is on the stack the remote side sends back some
988 // release request on the same logical UNO thread for an object that wants to acquire the
989 // SolarMutex in its destructor (e.g., SwXTextDocument in sw/inc/unotxdoc.hxx holding its
990 // m_pImpl via an sw::UnoImplPtr). While the correct approach would be to not make UNO calls
991 // with the SolarMutex (or any other mutex) locked, fixing that would probably be a heroic
992 // effort. So for now live with this hack, hoping that it does not introduce any new issues of
993 // its own:
994 static auto const tid = [] {
995 static sal_Int8 const id[] = {'r', 'e', 'l', 'e', 'a', 's', 'e', 'h', 'a', 'c', 'k'};
996 return rtl::ByteSequence(id, std::size(id));
997 }();
999 tid, oid, type,
1000 css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
1001 std::vector< BinaryAny >());
1002}
1003
1005 rtl::ByteSequence const & tid, OUString const & oid,
1006 css::uno::TypeDescription const & type,
1007 css::uno::TypeDescription const & member,
1008 std::vector< BinaryAny >&& inArguments)
1009{
1010 getWriter()->queueRequest(tid, oid, type, member, std::move(inArguments));
1011}
1012
1013void Bridge::throwException(bool exception, BinaryAny const & value) {
1014 if (exception) {
1016 }
1017}
1018
1019css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
1020 BinaryAny in(binaryAny);
1021 css::uno::Any out;
1022 out.~Any();
1024 &out, &in.get(),
1025 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
1026 binaryToCppMapping_.get());
1027 return out;
1028}
1029
1031 return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
1032}
1033
1035 if (unused) {
1036 // That the current thread considers the bridge unused implies that it
1037 // is not within an incoming or outgoing remote call (so calling
1038 // terminate cannot lead to deadlock):
1039 terminate(false);
1040 }
1041}
1042
1044 assert(state_ != STATE_INITIAL);
1045 if (state_ != STATE_STARTED) {
1046 throw css::lang::DisposedException(
1047 "Binary URP bridge already disposed",
1048 getXWeak());
1049 }
1050}
1051
1052}
1053
1054/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
void * rtlRandomPool
double d
uno_ThreadPool threadPool_
Definition: bridge.cxx:113
bool cleared_
Definition: bridge.cxx:146
rtl::ByteSequence tid_
Definition: bridge.cxx:114
OutgoingRequests & requests_
Definition: bridge.cxx:144
com::sun::star::uno::TypeDescription getType() const noexcept
Definition: binaryany.cxx:97
void * getValue(com::sun::star::uno::TypeDescription const &type) const noexcept
Definition: binaryany.cxx:101
~BinaryAny() noexcept
Definition: binaryany.cxx:80
uno_Any & get() noexcept
Definition: binaryany.hxx:51
com::sun::star::uno::Mapping binaryToCppMapping_
Definition: bridge.hxx:247
virtual ~Bridge() override
Definition: bridge.cxx:838
void sendRequest(rtl::ByteSequence const &tid, OUString const &oid, com::sun::star::uno::TypeDescription const &type, com::sun::star::uno::TypeDescription const &member, std::vector< BinaryAny > &&inArguments)
Definition: bridge.cxx:1004
void incrementActiveCalls() noexcept
Definition: bridge.cxx:569
void sendCommitChangeRequest()
Definition: bridge.cxx:952
virtual void SAL_CALL removeEventListener(com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > const &aListener) override
Definition: bridge.cxx:941
osl::Condition terminated_
Definition: bridge.hxx:259
void handleRequestChangeRequest(rtl::ByteSequence const &tid, std::vector< BinaryAny > const &inArguments)
Definition: bridge.cxx:714
rtl::Reference< Writer > writer_
Definition: bridge.hxx:265
std::vector< com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > > Listeners
Definition: bridge.hxx:225
void throwException(bool exception, BinaryAny const &value)
Definition: bridge.cxx:1013
uno_ThreadPool getThreadPool()
Definition: bridge.cxx:365
rtl::ByteSequence protPropTid_
Definition: bridge.hxx:248
com::sun::star::uno::Any mapBinaryToCppAny(BinaryAny const &binaryAny)
Definition: bridge.cxx:1019
void decrementActiveCalls() noexcept
Definition: bridge.cxx:578
void sendProtPropRequest(OutgoingRequest::Kind kind, std::vector< BinaryAny > const &inArguments)
Definition: bridge.cxx:960
void sendRequestChangeRequest()
Definition: bridge.cxx:624
com::sun::star::uno::Mapping cppToBinaryMapping_
Definition: bridge.hxx:246
com::sun::star::uno::TypeDescription protPropType_
Definition: bridge.hxx:250
bool currentContextMode_
Definition: bridge.hxx:267
virtual OUString SAL_CALL getDescription() override
Definition: bridge.cxx:907
void terminate(bool final)
Definition: bridge.cxx:232
uno_ThreadPool threadPool_
Definition: bridge.hxx:264
com::sun::star::uno::UnoInterfaceReference registerIncomingInterface(OUString const &oid, com::sun::star::uno::TypeDescription const &type)
Definition: bridge.cxx:379
void resurrectProxy(Proxy &proxy)
Definition: bridge.cxx:516
void decrementCalls()
Definition: bridge.cxx:558
virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > SAL_CALL getInstance(OUString const &sInstanceName) override
Definition: bridge.cxx:851
com::sun::star::uno::UnoInterfaceReference findStub(OUString const &oid, com::sun::star::uno::TypeDescription const &type)
Definition: bridge.cxx:459
std::map< com::sun::star::uno::TypeDescription, SubStub > Stub
Definition: bridge.hxx:227
std::map< OUString, Stub > Stubs
Definition: bridge.hxx:231
void terminateWhenUnused(bool unused)
Definition: bridge.cxx:1034
rtl::Reference< Reader > reader_
Definition: bridge.hxx:266
sal_Int32 random_
Definition: bridge.hxx:276
void freeProxy(Proxy &proxy)
Definition: bridge.cxx:532
OUString name_
Definition: bridge.hxx:240
void handleRequestChangeReply(bool exception, BinaryAny const &returnValue)
Definition: bridge.cxx:634
virtual void SAL_CALL dispose() override
Definition: bridge.cxx:912
std::size_t calls_
Definition: bridge.hxx:270
com::sun::star::uno::TypeDescription protPropCommit_
Definition: bridge.hxx:252
void setCurrentContextMode()
Definition: bridge.cxx:828
BinaryAny mapCppToBinaryAny(com::sun::star::uno::Any const &cppAny)
Definition: bridge.cxx:354
virtual void SAL_CALL addEventListener(com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > const &xListener) override
Definition: bridge.cxx:925
bool makeCall(OUString const &oid, com::sun::star::uno::TypeDescription const &member, bool setter, std::vector< BinaryAny > &&inArguments, BinaryAny *returnValue, std::vector< BinaryAny > *outArguments)
Definition: bridge.cxx:587
OutgoingRequest lastOutgoingRequest(rtl::ByteSequence const &tid)
Definition: bridge.cxx:816
std::mutex mutex_
Definition: bridge.hxx:261
OUString protPropOid_
Definition: bridge.hxx:249
com::sun::star::uno::TypeDescription protPropRequest_
Definition: bridge.hxx:251
void incrementCalls(bool normalCall) noexcept
Definition: bridge.cxx:551
Listeners listeners_
Definition: bridge.hxx:263
com::sun::star::uno::Reference< com::sun::star::connection::XConnection > connection_
Definition: bridge.hxx:242
void handleCommitChangeRequest(rtl::ByteSequence const &tid, std::vector< BinaryAny > const &inArguments)
Definition: bridge.cxx:765
void handleCommitChangeReply(bool exception, BinaryAny const &returnValue)
Definition: bridge.cxx:696
void releaseStub(OUString const &oid, com::sun::star::uno::TypeDescription const &type)
Definition: bridge.cxx:482
void checkDisposed()
Definition: bridge.cxx:1043
com::sun::star::uno::Environment binaryUno_
Definition: bridge.hxx:245
bool becameUnused() const
Definition: bridge.cxx:1030
rtl::Reference< BridgeFactory > factory_
Definition: bridge.hxx:239
bool isCurrentContextMode()
Definition: bridge.cxx:833
bool isProtocolPropertiesRequest(std::u16string_view oid, com::sun::star::uno::TypeDescription const &type) const
Definition: bridge.cxx:822
OUString registerOutgoingInterface(com::sun::star::uno::UnoInterfaceReference const &object, com::sun::star::uno::TypeDescription const &type)
Definition: bridge.cxx:412
osl::Condition passive_
Definition: bridge.hxx:254
OutgoingRequests outgoingRequests_
Definition: bridge.hxx:253
virtual OUString SAL_CALL getName() override
Definition: bridge.cxx:903
std::size_t activeCalls_
Definition: bridge.hxx:272
void makeReleaseCall(OUString const &oid, com::sun::star::uno::TypeDescription const &type)
Definition: bridge.cxx:977
void revokeProxy(Proxy &proxy)
Definition: bridge.cxx:527
std::size_t proxies_
Definition: bridge.hxx:269
rtl::Reference< Writer > getWriter()
Definition: bridge.cxx:372
void pop(rtl::ByteSequence const &tid) noexcept
OutgoingRequest top(rtl::ByteSequence const &tid)
const com::sun::star::uno::TypeDescription & getType() const
Definition: proxy.hxx:47
static bool isProxy(rtl::Reference< Bridge > const &bridge, com::sun::star::uno::UnoInterfaceReference const &object, OUString *oid)
const OUString & getOid() const
Definition: proxy.hxx:45
Any value
css::uno::Reference< css::lang::XMultiServiceFactory > provider_
void SAL_CALL uno_copyAndConvertData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
const char * name
void * p
sal_Int64 n
uno_Any a
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
int n2
struct _typelib_TypeDescription typelib_TypeDescription
css::uno::UnoInterfaceReference get()
void SAL_CALL throwException(Any const &exc)
Reference
int i
OUString toString(OptionInfo const *info)
sal_Int32 w
com::sun::star::uno::UnoInterfaceReference object
Definition: bridge.cxx:170
void SAL_CALL uno_releaseIdFromCurrentThread() SAL_THROW_EXTERN_C()
void SAL_CALL uno_getIdOfCurrentThread(sal_Sequence **ppThreadId) SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_enter(uno_ThreadPool hPool, void **ppJob) SAL_THROW_EXTERN_C()
uno_ThreadPool SAL_CALL uno_threadpool_create() SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_detach(SAL_UNUSED_PARAMETER uno_ThreadPool) SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_attach(uno_ThreadPool hPool) SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_destroy(uno_ThreadPool hPool) SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_dispose(uno_ThreadPool hPool) SAL_THROW_EXTERN_C()
sal_Bool SAL_CALL typelib_typedescription_isAssignableFrom(typelib_TypeDescription *pAssignable, typelib_TypeDescription *pFrom) SAL_THROW_EXTERN_C()
signed char sal_Int8
#define SAL_MAX_UINT32
ResultType type
OUString name_