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