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 0 : sal_Int32 random() {
77 : sal_Int32 n;
78 0 : rtlRandomPool pool = rtl_random_createPool();
79 0 : rtl_random_getBytes(pool, &n, sizeof n);
80 0 : rtl_random_destroyPool(pool);
81 0 : 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 0 : extern "C" void SAL_CALL freeProxyCallback(
91 : SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pProxy)
92 : {
93 : assert(pProxy != 0);
94 0 : static_cast< Proxy * >(pProxy)->do_free();
95 0 : }
96 :
97 0 : bool isThread(salhelper::Thread * thread) {
98 : assert(thread != 0);
99 0 : 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 0 : AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
116 0 : sal_Sequence * s = 0;
117 0 : uno_getIdOfCurrentThread(&s);
118 0 : tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
119 0 : uno_threadpool_attach(threadPool_);
120 0 : }
121 :
122 0 : AttachThread::~AttachThread() {
123 0 : uno_threadpool_detach(threadPool_);
124 0 : uno_releaseIdFromCurrentThread();
125 0 : }
126 :
127 0 : rtl::ByteSequence AttachThread::getTid() throw () {
128 0 : 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 0 : PopOutgoingRequest::PopOutgoingRequest(
148 : OutgoingRequests & requests, rtl::ByteSequence const & tid,
149 : OutgoingRequest const & request):
150 0 : requests_(requests), tid_(tid), cleared_(false)
151 : {
152 0 : requests_.push(tid_, request);
153 0 : }
154 :
155 0 : PopOutgoingRequest::~PopOutgoingRequest() {
156 0 : if (!cleared_) {
157 0 : requests_.pop(tid_);
158 : }
159 0 : }
160 :
161 0 : void PopOutgoingRequest::clear() {
162 0 : cleared_ = true;
163 0 : }
164 :
165 : }
166 :
167 0 : struct Bridge::SubStub {
168 : com::sun::star::uno::UnoInterfaceReference object;
169 :
170 : sal_uInt32 references;
171 : };
172 :
173 0 : 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 0 : RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
185 : protPropOid_("UrpProtocolProperties"),
186 : protPropType_(
187 : cppu::UnoType<
188 0 : 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 0 : mode_(MODE_REQUESTED)
194 : {
195 : assert(factory.is() && connection.is());
196 0 : if (!binaryUno_.is()) {
197 : throw css::uno::RuntimeException(
198 : "URP: no binary UNO environment",
199 0 : css::uno::Reference< css::uno::XInterface >());
200 : }
201 0 : 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 0 : passive_.set();
207 0 : }
208 :
209 0 : void Bridge::start() {
210 0 : rtl::Reference< Reader > r(new Reader(this));
211 0 : rtl::Reference< Writer > w(new Writer(this));
212 : {
213 0 : osl::MutexGuard g(mutex_);
214 : assert(
215 : state_ == STATE_INITIAL && threadPool_ == 0 && !writer_.is() &&
216 : !reader_.is());
217 0 : threadPool_ = uno_threadpool_create();
218 : assert(threadPool_ != 0);
219 0 : reader_ = r;
220 0 : writer_ = w;
221 0 : 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 0 : w->launch();
230 0 : r->launch();
231 0 : }
232 :
233 0 : 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 0 : rtl::Reference< Reader > r;
239 0 : rtl::Reference< Writer > w;
240 : bool joinW;
241 0 : Listeners ls;
242 : {
243 0 : osl::ClearableMutexGuard g(mutex_);
244 0 : switch (state_) {
245 : case STATE_INITIAL: // via ~Bridge -> dispose -> terminate
246 : case STATE_FINAL:
247 0 : return;
248 : case STATE_STARTED:
249 0 : break;
250 : case STATE_TERMINATED:
251 0 : if (final) {
252 0 : g.clear();
253 0 : terminated_.wait();
254 : {
255 0 : osl::MutexGuard g2(mutex_);
256 0 : tp = threadPool_;
257 0 : threadPool_ = 0;
258 0 : if (reader_.is()) {
259 0 : if (!isThread(reader_.get())) {
260 0 : r = reader_;
261 : }
262 0 : reader_.clear();
263 : }
264 0 : if (writer_.is()) {
265 0 : if (!isThread(writer_.get())) {
266 0 : w = writer_;
267 : }
268 0 : writer_.clear();
269 : }
270 0 : state_ = STATE_FINAL;
271 : }
272 : assert(!(r.is() && w.is()));
273 0 : if (r.is()) {
274 0 : r->join();
275 0 : } else if (w.is()) {
276 0 : w->join();
277 : }
278 0 : if (tp != 0) {
279 0 : uno_threadpool_destroy(tp);
280 : }
281 : }
282 0 : return;
283 : }
284 0 : tp = threadPool_;
285 : assert(!(final && isThread(reader_.get())));
286 0 : if (!isThread(reader_.get())) {
287 0 : std::swap(reader_, r);
288 : }
289 0 : w = writer_;
290 0 : joinW = !isThread(writer_.get());
291 : assert(!final || joinW);
292 0 : if (joinW) {
293 0 : writer_.clear();
294 : }
295 0 : ls.swap(listeners_);
296 0 : state_ = final ? STATE_FINAL : STATE_TERMINATED;
297 : }
298 : try {
299 0 : 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 0 : w->stop();
305 0 : if (r.is()) {
306 0 : r->join();
307 : }
308 0 : if (joinW) {
309 0 : w->join();
310 : }
311 : assert(tp != 0);
312 0 : uno_threadpool_dispose(tp);
313 0 : Stubs s;
314 : {
315 0 : osl::MutexGuard g(mutex_);
316 0 : s.swap(stubs_);
317 : }
318 0 : for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
319 0 : 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 0 : binaryUno_.get()->pExtEnv->revokeInterface(
326 0 : binaryUno_.get()->pExtEnv, j->second.object.get());
327 : }
328 : }
329 0 : factory_->removeBridge(this);
330 0 : for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
331 : try {
332 0 : (*i)->disposing(
333 : css::lang::EventObject(
334 0 : 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 0 : }
341 : }
342 0 : if (final) {
343 0 : uno_threadpool_destroy(tp);
344 : }
345 : {
346 0 : osl::MutexGuard g(mutex_);
347 0 : if (final) {
348 0 : threadPool_ = 0;
349 0 : }
350 : }
351 0 : terminated_.set();
352 : }
353 :
354 0 : css::uno::Reference< css::connection::XConnection > Bridge::getConnection()
355 : const
356 : {
357 0 : return connection_;
358 : }
359 :
360 0 : css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider()
361 : const
362 : {
363 0 : return provider_;
364 : }
365 :
366 0 : css::uno::Mapping & Bridge::getCppToBinaryMapping() {
367 0 : return cppToBinaryMapping_;
368 : }
369 :
370 0 : BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
371 0 : css::uno::Any in(cppAny);
372 0 : BinaryAny out;
373 0 : out.~BinaryAny();
374 : uno_copyAndConvertData(
375 0 : out.get(), &in,
376 0 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
377 0 : cppToBinaryMapping_.get());
378 0 : return out;
379 : }
380 :
381 0 : uno_ThreadPool Bridge::getThreadPool() {
382 0 : osl::MutexGuard g(mutex_);
383 0 : checkDisposed();
384 : assert(threadPool_ != 0);
385 0 : return threadPool_;
386 : }
387 :
388 0 : rtl::Reference< Writer > Bridge::getWriter() {
389 0 : osl::MutexGuard g(mutex_);
390 0 : checkDisposed();
391 : assert(writer_.is());
392 0 : return writer_;
393 : }
394 :
395 0 : css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
396 : OUString const & oid, css::uno::TypeDescription const & type)
397 : {
398 : assert(type.is());
399 0 : if (oid.isEmpty()) {
400 0 : return css::uno::UnoInterfaceReference();
401 : }
402 0 : css::uno::UnoInterfaceReference obj(findStub(oid, type));
403 0 : if (!obj.is()) {
404 0 : binaryUno_.get()->pExtEnv->getRegisteredInterface(
405 0 : binaryUno_.get()->pExtEnv,
406 : reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
407 0 : reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
408 0 : if (obj.is()) {
409 0 : makeReleaseCall(oid, type);
410 : } else {
411 0 : obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
412 : {
413 0 : osl::MutexGuard g(mutex_);
414 : assert(proxies_ < std::numeric_limits< std::size_t >::max());
415 0 : ++proxies_;
416 : }
417 0 : binaryUno_.get()->pExtEnv->registerProxyInterface(
418 0 : binaryUno_.get()->pExtEnv,
419 : reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
420 : oid.pData,
421 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
422 0 : type.get()));
423 : }
424 : }
425 0 : return obj;
426 : }
427 :
428 0 : OUString Bridge::registerOutgoingInterface(
429 : css::uno::UnoInterfaceReference const & object,
430 : css::uno::TypeDescription const & type)
431 : {
432 : assert(type.is());
433 0 : if (!object.is()) {
434 0 : return OUString();
435 : }
436 0 : OUString oid;
437 0 : if (!Proxy::isProxy(this, object, &oid)) {
438 0 : binaryUno_.get()->pExtEnv->getObjectIdentifier(
439 0 : binaryUno_.get()->pExtEnv, &oid.pData, object.get());
440 0 : osl::MutexGuard g(mutex_);
441 0 : Stubs::iterator i(stubs_.find(oid));
442 0 : Stub newStub;
443 0 : Stub * stub = i == stubs_.end() ? &newStub : &i->second;
444 0 : 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 0 : if (j == stub->end()) {
448 0 : j = stub->insert(Stub::value_type(type, SubStub())).first;
449 0 : if (stub == &newStub) {
450 0 : i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
451 0 : std::swap(i->second, newStub);
452 0 : j = i->second.find(type);
453 : assert(j != i->second.end());
454 : }
455 0 : j->second.object = object;
456 0 : j->second.references = 1;
457 0 : binaryUno_.get()->pExtEnv->registerInterface(
458 0 : binaryUno_.get()->pExtEnv,
459 0 : reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
460 : oid.pData,
461 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
462 0 : type.get()));
463 : } else {
464 : assert(stub != &newStub);
465 0 : 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 0 : ++j->second.references;
471 0 : }
472 : }
473 0 : return oid;
474 : }
475 :
476 0 : css::uno::UnoInterfaceReference Bridge::findStub(
477 : OUString const & oid, css::uno::TypeDescription const & type)
478 : {
479 : assert(!oid.isEmpty() && type.is());
480 0 : osl::MutexGuard g(mutex_);
481 0 : Stubs::iterator i(stubs_.find(oid));
482 0 : if (i != stubs_.end()) {
483 0 : Stub::iterator j(i->second.find(type));
484 0 : if (j != i->second.end()) {
485 0 : return j->second.object;
486 : }
487 0 : for (j = i->second.begin(); j != i->second.end(); ++j) {
488 0 : if (typelib_typedescription_isAssignableFrom(
489 0 : type.get(), j->first.get()))
490 : {
491 0 : return j->second.object;
492 : }
493 : }
494 : }
495 0 : return css::uno::UnoInterfaceReference();
496 : }
497 :
498 0 : void Bridge::releaseStub(
499 : OUString const & oid, css::uno::TypeDescription const & type)
500 : {
501 : assert(!oid.isEmpty() && type.is());
502 0 : css::uno::UnoInterfaceReference obj;
503 : bool unused;
504 : {
505 0 : osl::MutexGuard g(mutex_);
506 0 : Stubs::iterator i(stubs_.find(oid));
507 0 : if (i == stubs_.end()) {
508 : throw css::uno::RuntimeException(
509 : "URP: release unknown stub",
510 0 : css::uno::Reference< css::uno::XInterface >());
511 : }
512 0 : Stub::iterator j(i->second.find(type));
513 0 : 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 0 : --j->second.references;
520 0 : if (j->second.references == 0) {
521 0 : obj = j->second.object;
522 0 : i->second.erase(j);
523 0 : if (i->second.empty()) {
524 0 : stubs_.erase(i);
525 : }
526 : }
527 0 : unused = becameUnused();
528 : }
529 0 : if (obj.is()) {
530 0 : binaryUno_.get()->pExtEnv->revokeInterface(
531 0 : binaryUno_.get()->pExtEnv, obj.get());
532 : }
533 0 : terminateWhenUnused(unused);
534 0 : }
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 0 : void Bridge::revokeProxy(Proxy & proxy) {
548 0 : binaryUno_.get()->pExtEnv->revokeInterface(
549 0 : binaryUno_.get()->pExtEnv, &proxy);
550 0 : }
551 :
552 0 : void Bridge::freeProxy(Proxy & proxy) {
553 : try {
554 0 : makeReleaseCall(proxy.getOid(), proxy.getType());
555 0 : } 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 0 : osl::MutexGuard g(mutex_);
564 : assert(proxies_ > 0);
565 0 : --proxies_;
566 0 : unused = becameUnused();
567 : }
568 0 : terminateWhenUnused(unused);
569 0 : }
570 :
571 0 : void Bridge::incrementCalls(bool normalCall) throw () {
572 0 : osl::MutexGuard g(mutex_);
573 : assert(calls_ < std::numeric_limits< std::size_t >::max());
574 0 : ++calls_;
575 0 : normalCall_ |= normalCall;
576 0 : }
577 :
578 0 : void Bridge::decrementCalls() {
579 : bool unused;
580 : {
581 0 : osl::MutexGuard g(mutex_);
582 : assert(calls_ > 0);
583 0 : --calls_;
584 0 : unused = becameUnused();
585 : }
586 0 : terminateWhenUnused(unused);
587 0 : }
588 :
589 0 : void Bridge::incrementActiveCalls() throw () {
590 0 : osl::MutexGuard g(mutex_);
591 : assert(
592 : activeCalls_ <= calls_ &&
593 : activeCalls_ < std::numeric_limits< std::size_t >::max());
594 0 : ++activeCalls_;
595 0 : passive_.reset();
596 0 : }
597 :
598 0 : void Bridge::decrementActiveCalls() throw () {
599 0 : osl::MutexGuard g(mutex_);
600 : assert(activeCalls_ <= calls_ && activeCalls_ > 0);
601 0 : --activeCalls_;
602 0 : if (activeCalls_ == 0) {
603 0 : passive_.set();
604 0 : }
605 0 : }
606 :
607 0 : 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 0 : boost::scoped_ptr< IncomingReply > resp;
613 : {
614 0 : uno_ThreadPool tp = getThreadPool();
615 0 : AttachThread att(tp);
616 : PopOutgoingRequest pop(
617 : outgoingRequests_, att.getTid(),
618 0 : OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
619 : sendRequest(
620 : att.getTid(), oid, css::uno::TypeDescription(), member,
621 0 : inArguments);
622 0 : pop.clear();
623 0 : incrementCalls(true);
624 0 : incrementActiveCalls();
625 : void * job;
626 0 : uno_threadpool_enter(tp, &job);
627 0 : resp.reset(static_cast< IncomingReply * >(job));
628 0 : decrementActiveCalls();
629 0 : decrementCalls();
630 : }
631 0 : 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 0 : *returnValue = resp->returnValue;
637 0 : if (!resp->exception) {
638 0 : *outArguments = resp->outArguments;
639 : }
640 0 : return resp->exception;
641 : }
642 :
643 0 : void Bridge::sendRequestChangeRequest() {
644 : assert(mode_ == MODE_REQUESTED);
645 0 : random_ = random();
646 0 : std::vector< BinaryAny > a;
647 : a.push_back(
648 : BinaryAny(
649 0 : css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
650 0 : &random_));
651 0 : sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
652 0 : }
653 :
654 0 : void Bridge::handleRequestChangeReply(
655 : bool exception, BinaryAny const & returnValue)
656 : {
657 : try {
658 0 : 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 0 : return;
674 : }
675 : sal_Int32 n = *static_cast< sal_Int32 * >(
676 : returnValue.getValue(
677 0 : css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
678 0 : sal_Int32 exp = 0;
679 0 : switch (mode_) {
680 : case MODE_REQUESTED:
681 : case MODE_REPLY_1:
682 0 : exp = 1;
683 0 : break;
684 : case MODE_REPLY_MINUS1:
685 0 : exp = -1;
686 0 : mode_ = MODE_REQUESTED;
687 0 : break;
688 : case MODE_REPLY_0:
689 0 : exp = 0;
690 0 : mode_ = MODE_WAIT;
691 0 : break;
692 : default:
693 : assert(false); // this cannot happen
694 0 : break;
695 : }
696 0 : 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 0 : decrementCalls();
702 0 : switch (exp) {
703 : case -1:
704 0 : sendRequestChangeRequest();
705 0 : break;
706 : case 0:
707 0 : break;
708 : case 1:
709 0 : sendCommitChangeRequest();
710 0 : break;
711 : default:
712 : assert(false); // this cannot happen
713 0 : break;
714 : }
715 : }
716 :
717 0 : void Bridge::handleCommitChangeReply(
718 : bool exception, BinaryAny const & returnValue)
719 : {
720 0 : bool ccMode = true;
721 : try {
722 0 : throwException(exception, returnValue);
723 0 : } catch (const css::bridge::InvalidProtocolChangeException &) {
724 0 : ccMode = false;
725 : }
726 0 : if (ccMode) {
727 0 : setCurrentContextMode();
728 : }
729 : assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
730 0 : mode_ = MODE_NORMAL;
731 0 : getWriter()->unblock();
732 0 : decrementCalls();
733 0 : }
734 :
735 0 : void Bridge::handleRequestChangeRequest(
736 : rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
737 : {
738 : assert(inArguments.size() == 1);
739 0 : switch (mode_) {
740 : case MODE_REQUESTED:
741 : {
742 : sal_Int32 n2 = *static_cast< sal_Int32 * >(
743 0 : inArguments[0].getValue(
744 : css::uno::TypeDescription(
745 0 : cppu::UnoType< sal_Int32 >::get())));
746 : sal_Int32 ret;
747 0 : if (n2 > random_) {
748 0 : ret = 1;
749 0 : mode_ = MODE_REPLY_0;
750 0 : } else if (n2 == random_) {
751 0 : ret = -1;
752 0 : mode_ = MODE_REPLY_MINUS1;
753 : } else {
754 0 : ret = 0;
755 0 : mode_ = MODE_REPLY_1;
756 : }
757 : getWriter()->sendDirectReply(
758 : tid, protPropRequest_, false,
759 : BinaryAny(
760 : css::uno::TypeDescription(
761 0 : cppu::UnoType< sal_Int32 >::get()),
762 : &ret),
763 0 : std::vector< BinaryAny >());
764 0 : 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 0 : }
785 :
786 0 : void Bridge::handleCommitChangeRequest(
787 : rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
788 : {
789 0 : bool ccMode = false;
790 0 : bool exc = false;
791 0 : BinaryAny ret;
792 : assert(inArguments.size() == 1);
793 0 : css::uno::Sequence< css::bridge::ProtocolProperty > s;
794 0 : bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
795 : assert(ok);
796 : (void) ok; // avoid warnings
797 0 : for (sal_Int32 i = 0; i != s.getLength(); ++i) {
798 0 : if (s[i].Name == "CurrentContext") {
799 0 : 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 0 : switch (mode_) {
813 : case MODE_WAIT:
814 : getWriter()->sendDirectReply(
815 0 : tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
816 0 : if (ccMode) {
817 0 : setCurrentContextMode();
818 0 : mode_ = MODE_NORMAL;
819 0 : getWriter()->unblock();
820 : } else {
821 0 : mode_ = MODE_REQUESTED;
822 0 : sendRequestChangeRequest();
823 : }
824 0 : 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 0 : }
836 0 : }
837 :
838 0 : OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
839 0 : OutgoingRequest req(outgoingRequests_.top(tid));
840 0 : outgoingRequests_.pop(tid);
841 0 : return req;
842 : }
843 :
844 0 : bool Bridge::isProtocolPropertiesRequest(
845 : OUString const & oid, css::uno::TypeDescription const & type) const
846 : {
847 0 : return oid == protPropOid_ && type.equals(protPropType_);
848 : }
849 :
850 0 : void Bridge::setCurrentContextMode() {
851 0 : osl::MutexGuard g(mutex_);
852 0 : currentContextMode_ = true;
853 0 : }
854 :
855 0 : bool Bridge::isCurrentContextMode() {
856 0 : osl::MutexGuard g(mutex_);
857 0 : return currentContextMode_;
858 : }
859 :
860 0 : 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 0 : dispose();
870 0 : }
871 :
872 0 : css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
873 : OUString const & sInstanceName) throw (css::uno::RuntimeException, std::exception)
874 : {
875 0 : 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 0 : for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
881 0 : 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 0 : cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get());
890 0 : typelib_TypeDescription * p = ifc.get();
891 0 : std::vector< BinaryAny > inArgs;
892 : inArgs.push_back(
893 : BinaryAny(
894 0 : css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
895 0 : &p));
896 0 : BinaryAny ret;
897 0 : std::vector< BinaryAny> outArgs;
898 : bool exc = makeCall(
899 : sInstanceName,
900 : css::uno::TypeDescription(
901 : "com.sun.star.uno.XInterface::queryInterface"),
902 0 : false, inArgs, &ret, &outArgs);
903 0 : throwException(exc, ret);
904 : return css::uno::Reference< css::uno::XInterface >(
905 : static_cast< css::uno::XInterface * >(
906 : binaryToCppMapping_.mapInterface(
907 0 : *static_cast< uno_Interface ** >(ret.getValue(ifc)),
908 0 : ifc.get())),
909 0 : css::uno::UNO_REF_NO_ACQUIRE);
910 : }
911 :
912 0 : OUString Bridge::getName() throw (css::uno::RuntimeException, std::exception) {
913 0 : 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 0 : 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 0 : 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 0 : passive_.wait();
934 0 : }
935 :
936 0 : 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 0 : osl::MutexGuard g(mutex_);
943 : assert(state_ != STATE_INITIAL);
944 0 : if (state_ == STATE_STARTED) {
945 0 : listeners_.push_back(xListener);
946 0 : 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 0 : void Bridge::sendCommitChangeRequest() {
966 : assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
967 0 : css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
968 0 : s[0].Name = "CurrentContext";
969 0 : std::vector< BinaryAny > a;
970 0 : a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
971 0 : sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
972 0 : }
973 :
974 0 : 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 0 : incrementCalls(false);
981 : css::uno::TypeDescription member(
982 : kind == OutgoingRequest::KIND_REQUEST_CHANGE
983 0 : ? protPropRequest_ : protPropCommit_);
984 : PopOutgoingRequest pop(
985 0 : outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
986 : getWriter()->sendDirectRequest(
987 0 : protPropTid_, protPropOid_, protPropType_, member, inArguments);
988 0 : pop.clear();
989 0 : }
990 :
991 0 : void Bridge::makeReleaseCall(
992 : OUString const & oid, css::uno::TypeDescription const & type)
993 : {
994 0 : AttachThread att(getThreadPool());
995 : sendRequest(
996 : att.getTid(), oid, type,
997 : css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
998 0 : std::vector< BinaryAny >());
999 0 : }
1000 :
1001 0 : 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 0 : getWriter()->queueRequest(tid, oid, type, member, inArguments);
1008 0 : }
1009 :
1010 0 : void Bridge::throwException(bool exception, BinaryAny const & value) {
1011 0 : if (exception) {
1012 0 : cppu::throwException(mapBinaryToCppAny(value));
1013 : }
1014 0 : }
1015 :
1016 0 : css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
1017 0 : BinaryAny in(binaryAny);
1018 0 : css::uno::Any out;
1019 0 : out.~Any();
1020 : uno_copyAndConvertData(
1021 0 : &out, in.get(),
1022 0 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
1023 0 : binaryToCppMapping_.get());
1024 0 : return out;
1025 : }
1026 :
1027 0 : bool Bridge::becameUnused() const {
1028 0 : return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
1029 : }
1030 :
1031 0 : void Bridge::terminateWhenUnused(bool unused) {
1032 0 : 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 0 : terminate(false);
1037 : }
1038 0 : }
1039 :
1040 0 : void Bridge::checkDisposed() {
1041 : assert(state_ != STATE_INITIAL);
1042 0 : if (state_ != STATE_STARTED) {
1043 : throw css::lang::DisposedException(
1044 : "Binary URP bridge already disposed",
1045 0 : static_cast< cppu::OWeakObject * >(this));
1046 : }
1047 0 : }
1048 :
1049 : }
1050 :
1051 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|