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