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