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