Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "sal/config.h"
21 :
22 : #include <algorithm>
23 : #include <cassert>
24 : #include <cstddef>
25 : #include <limits>
26 : #include <memory>
27 : #include <vector>
28 :
29 : #include "boost/noncopyable.hpp"
30 : #include "com/sun/star/bridge/InvalidProtocolChangeException.hpp"
31 : #include "com/sun/star/bridge/XBridge.hpp"
32 : #include "com/sun/star/bridge/XInstanceProvider.hpp"
33 : #include "com/sun/star/bridge/XProtocolProperties.hpp"
34 : #include "com/sun/star/connection/XConnection.hpp"
35 : #include "com/sun/star/io/IOException.hpp"
36 : #include "com/sun/star/lang/DisposedException.hpp"
37 : #include "com/sun/star/lang/EventObject.hpp"
38 : #include "com/sun/star/lang/XEventListener.hpp"
39 : #include "com/sun/star/uno/Reference.hxx"
40 : #include "com/sun/star/uno/RuntimeException.hpp"
41 : #include "com/sun/star/uno/Sequence.hxx"
42 : #include "com/sun/star/uno/XInterface.hpp"
43 : #include "cppuhelper/exc_hlp.hxx"
44 : #include "cppuhelper/weak.hxx"
45 : #include "osl/mutex.hxx"
46 : #include "osl/thread.hxx"
47 : #include "rtl/byteseq.hxx"
48 : #include "rtl/random.h"
49 : #include "rtl/ref.hxx"
50 : #include "rtl/ustrbuf.hxx"
51 : #include "rtl/ustring.h"
52 : #include "rtl/ustring.hxx"
53 : #include "sal/log.hxx"
54 : #include "sal/types.h"
55 : #include "typelib/typeclass.h"
56 : #include "typelib/typedescription.h"
57 : #include "typelib/typedescription.hxx"
58 : #include "uno/dispatcher.hxx"
59 : #include "uno/environment.hxx"
60 : #include "uno/lbnames.h"
61 :
62 : #include "binaryany.hxx"
63 : #include "bridge.hxx"
64 : #include "bridgefactory.hxx"
65 : #include "incomingreply.hxx"
66 : #include "lessoperators.hxx"
67 : #include "outgoingrequest.hxx"
68 : #include "outgoingrequests.hxx"
69 : #include "proxy.hxx"
70 : #include "reader.hxx"
71 :
72 : namespace binaryurp {
73 :
74 : namespace {
75 :
76 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 : RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
185 : protPropOid_(RTL_CONSTASCII_USTRINGPARAM("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 : 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 : assert(!(reader_.is() && isThread(reader_.get())));
259 0 : std::swap(reader_, r);
260 : assert(!(writer_.is() && isThread(writer_.get())));
261 0 : std::swap(writer_, w);
262 0 : state_ = STATE_FINAL;
263 : }
264 : assert(!(r.is() && w.is()));
265 0 : if (r.is()) {
266 0 : r->join();
267 0 : } else if (w.is()) {
268 0 : w->join();
269 : }
270 0 : if (tp != 0) {
271 0 : uno_threadpool_destroy(tp);
272 : }
273 : }
274 : return;
275 : }
276 0 : tp = threadPool_;
277 : assert(!(final && isThread(reader_.get())));
278 0 : if (!isThread(reader_.get())) {
279 0 : std::swap(reader_, r);
280 : }
281 0 : w = writer_;
282 0 : joinW = !isThread(writer_.get());
283 : assert(!final || joinW);
284 0 : if (joinW) {
285 0 : writer_.clear();
286 : }
287 0 : ls.swap(listeners_);
288 0 : state_ = final ? STATE_FINAL : STATE_TERMINATED;
289 : }
290 : try {
291 0 : connection_->close();
292 0 : } catch (const css::io::IOException & e) {
293 : SAL_INFO("binaryurp", "caught IO exception '" << e.Message << '\'');
294 : }
295 : assert(w.is());
296 0 : w->stop();
297 0 : if (r.is()) {
298 0 : r->join();
299 : }
300 0 : if (joinW) {
301 0 : w->join();
302 : }
303 : assert(tp != 0);
304 0 : uno_threadpool_dispose(tp);
305 0 : Stubs s;
306 : {
307 0 : osl::MutexGuard g(mutex_);
308 0 : s.swap(stubs_);
309 : }
310 0 : for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
311 0 : for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j)
312 : {
313 : SAL_INFO(
314 : "binaryurp",
315 : "stub '" << i->first << "', '" << toString(j->first)
316 : << "' still mapped at Bridge::terminate");
317 0 : binaryUno_.get()->pExtEnv->revokeInterface(
318 0 : binaryUno_.get()->pExtEnv, j->second.object.get());
319 : }
320 : }
321 0 : factory_->removeBridge(this);
322 0 : for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
323 : try {
324 0 : (*i)->disposing(
325 : css::lang::EventObject(
326 0 : static_cast< cppu::OWeakObject * >(this)));
327 0 : } catch (const css::uno::RuntimeException & e) {
328 : SAL_WARN(
329 : "binaryurp",
330 : "caught runtime exception '" << e.Message << '\'');
331 : }
332 0 : }
333 : }
334 0 : if (final) {
335 0 : uno_threadpool_destroy(tp);
336 : }
337 : {
338 0 : osl::MutexGuard g(mutex_);
339 0 : if (final) {
340 0 : threadPool_ = 0;
341 0 : }
342 : }
343 0 : terminated_.set();
344 : }
345 :
346 0 : css::uno::Reference< css::connection::XConnection > Bridge::getConnection()
347 : const
348 : {
349 0 : return connection_;
350 : }
351 :
352 0 : css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider()
353 : const
354 : {
355 0 : return provider_;
356 : }
357 :
358 0 : css::uno::Mapping & Bridge::getCppToBinaryMapping() {
359 0 : return cppToBinaryMapping_;
360 : }
361 :
362 0 : BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
363 0 : css::uno::Any in(cppAny);
364 0 : BinaryAny out;
365 0 : out.~BinaryAny();
366 : uno_copyAndConvertData(
367 0 : out.get(), &in,
368 0 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
369 0 : cppToBinaryMapping_.get());
370 0 : return out;
371 : }
372 :
373 0 : uno_ThreadPool Bridge::getThreadPool() {
374 0 : osl::MutexGuard g(mutex_);
375 0 : checkDisposed();
376 : assert(threadPool_ != 0);
377 0 : return threadPool_;
378 : }
379 :
380 0 : rtl::Reference< Writer > Bridge::getWriter() {
381 0 : osl::MutexGuard g(mutex_);
382 0 : checkDisposed();
383 : assert(writer_.is());
384 0 : return writer_;
385 : }
386 :
387 0 : css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
388 : OUString const & oid, css::uno::TypeDescription const & type)
389 : {
390 : assert(type.is());
391 0 : if (oid.isEmpty()) {
392 0 : return css::uno::UnoInterfaceReference();
393 : }
394 0 : css::uno::UnoInterfaceReference obj(findStub(oid, type));
395 0 : if (!obj.is()) {
396 0 : binaryUno_.get()->pExtEnv->getRegisteredInterface(
397 0 : binaryUno_.get()->pExtEnv,
398 : reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
399 0 : reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
400 0 : if (obj.is()) {
401 0 : makeReleaseCall(oid, type);
402 : } else {
403 0 : obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
404 : {
405 0 : osl::MutexGuard g(mutex_);
406 : assert(proxies_ < std::numeric_limits< std::size_t >::max());
407 0 : ++proxies_;
408 : }
409 0 : binaryUno_.get()->pExtEnv->registerProxyInterface(
410 0 : binaryUno_.get()->pExtEnv,
411 : reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
412 : oid.pData,
413 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
414 0 : type.get()));
415 : }
416 : }
417 0 : return obj;
418 : }
419 :
420 0 : OUString Bridge::registerOutgoingInterface(
421 : css::uno::UnoInterfaceReference const & object,
422 : css::uno::TypeDescription const & type)
423 : {
424 : assert(type.is());
425 0 : if (!object.is()) {
426 0 : return OUString();
427 : }
428 0 : OUString oid;
429 0 : if (!Proxy::isProxy(this, object, &oid)) {
430 0 : binaryUno_.get()->pExtEnv->getObjectIdentifier(
431 0 : binaryUno_.get()->pExtEnv, &oid.pData, object.get());
432 0 : osl::MutexGuard g(mutex_);
433 0 : Stubs::iterator i(stubs_.find(oid));
434 0 : Stub newStub;
435 0 : Stub * stub = i == stubs_.end() ? &newStub : &i->second;
436 0 : Stub::iterator j(stub->find(type));
437 : //TODO: Release sub-stub if it is not successfully sent to remote side
438 : // (otherwise, stub will leak until terminate()):
439 0 : if (j == stub->end()) {
440 0 : j = stub->insert(Stub::value_type(type, SubStub())).first;
441 0 : if (stub == &newStub) {
442 0 : i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
443 0 : std::swap(i->second, newStub);
444 0 : j = i->second.find(type);
445 : assert(j != i->second.end());
446 : }
447 0 : j->second.object = object;
448 0 : j->second.references = 1;
449 0 : binaryUno_.get()->pExtEnv->registerInterface(
450 0 : binaryUno_.get()->pExtEnv,
451 0 : reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
452 : oid.pData,
453 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
454 0 : type.get()));
455 : } else {
456 : assert(stub != &newStub);
457 0 : if (j->second.references == SAL_MAX_UINT32) {
458 : throw css::uno::RuntimeException(
459 : "URP: stub reference count overflow",
460 0 : css::uno::Reference< css::uno::XInterface >());
461 : }
462 0 : ++j->second.references;
463 0 : }
464 : }
465 0 : return oid;
466 : }
467 :
468 0 : css::uno::UnoInterfaceReference Bridge::findStub(
469 : OUString const & oid, css::uno::TypeDescription const & type)
470 : {
471 : assert(!oid.isEmpty() && type.is());
472 0 : osl::MutexGuard g(mutex_);
473 0 : Stubs::iterator i(stubs_.find(oid));
474 0 : if (i != stubs_.end()) {
475 0 : Stub::iterator j(i->second.find(type));
476 0 : if (j != i->second.end()) {
477 0 : return j->second.object;
478 : }
479 0 : for (j = i->second.begin(); j != i->second.end(); ++j) {
480 0 : if (typelib_typedescription_isAssignableFrom(
481 0 : type.get(), j->first.get()))
482 : {
483 0 : return j->second.object;
484 : }
485 : }
486 : }
487 0 : return css::uno::UnoInterfaceReference();
488 : }
489 :
490 0 : void Bridge::releaseStub(
491 : OUString const & oid, css::uno::TypeDescription const & type)
492 : {
493 : assert(!oid.isEmpty() && type.is());
494 0 : css::uno::UnoInterfaceReference obj;
495 : bool unused;
496 : {
497 0 : osl::MutexGuard g(mutex_);
498 0 : Stubs::iterator i(stubs_.find(oid));
499 0 : if (i == stubs_.end()) {
500 : throw css::uno::RuntimeException(
501 : "URP: release unknown stub",
502 0 : css::uno::Reference< css::uno::XInterface >());
503 : }
504 0 : Stub::iterator j(i->second.find(type));
505 0 : if (j == i->second.end()) {
506 : throw css::uno::RuntimeException(
507 : "URP: release unknown stub",
508 0 : css::uno::Reference< css::uno::XInterface >());
509 : }
510 : assert(j->second.references > 0);
511 0 : --j->second.references;
512 0 : if (j->second.references == 0) {
513 0 : obj = j->second.object;
514 0 : i->second.erase(j);
515 0 : if (i->second.empty()) {
516 0 : stubs_.erase(i);
517 : }
518 : }
519 0 : unused = becameUnused();
520 : }
521 0 : if (obj.is()) {
522 0 : binaryUno_.get()->pExtEnv->revokeInterface(
523 0 : binaryUno_.get()->pExtEnv, obj.get());
524 : }
525 0 : terminateWhenUnused(unused);
526 0 : }
527 :
528 0 : void Bridge::resurrectProxy(Proxy & proxy) {
529 0 : uno_Interface * p = &proxy;
530 0 : binaryUno_.get()->pExtEnv->registerProxyInterface(
531 0 : binaryUno_.get()->pExtEnv,
532 : reinterpret_cast< void ** >(&p), &freeProxyCallback,
533 : proxy.getOid().pData,
534 : reinterpret_cast< typelib_InterfaceTypeDescription * >(
535 0 : proxy.getType().get()));
536 : assert(p == &proxy);
537 0 : }
538 :
539 0 : void Bridge::revokeProxy(Proxy & proxy) {
540 0 : binaryUno_.get()->pExtEnv->revokeInterface(
541 0 : binaryUno_.get()->pExtEnv, &proxy);
542 0 : }
543 :
544 0 : void Bridge::freeProxy(Proxy & proxy) {
545 : try {
546 0 : makeReleaseCall(proxy.getOid(), proxy.getType());
547 0 : } catch (const css::uno::RuntimeException & e) {
548 : SAL_INFO(
549 : "binaryurp", "caught runtime exception '" << e.Message << '\'');
550 0 : } catch (const std::exception & e) {
551 : SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
552 : }
553 : bool unused;
554 : {
555 0 : osl::MutexGuard g(mutex_);
556 : assert(proxies_ > 0);
557 0 : --proxies_;
558 0 : unused = becameUnused();
559 : }
560 0 : terminateWhenUnused(unused);
561 0 : }
562 :
563 0 : void Bridge::incrementCalls(bool normalCall) throw () {
564 0 : osl::MutexGuard g(mutex_);
565 : assert(calls_ < std::numeric_limits< std::size_t >::max());
566 0 : ++calls_;
567 0 : normalCall_ |= normalCall;
568 0 : }
569 :
570 0 : void Bridge::decrementCalls() {
571 : bool unused;
572 : {
573 0 : osl::MutexGuard g(mutex_);
574 : assert(calls_ > 0);
575 0 : --calls_;
576 0 : unused = becameUnused();
577 : }
578 0 : terminateWhenUnused(unused);
579 0 : }
580 :
581 0 : void Bridge::incrementActiveCalls() throw () {
582 0 : osl::MutexGuard g(mutex_);
583 : assert(
584 : activeCalls_ <= calls_ &&
585 : activeCalls_ < std::numeric_limits< std::size_t >::max());
586 0 : ++activeCalls_;
587 0 : passive_.reset();
588 0 : }
589 :
590 0 : void Bridge::decrementActiveCalls() throw () {
591 0 : osl::MutexGuard g(mutex_);
592 : assert(activeCalls_ <= calls_ && activeCalls_ > 0);
593 0 : --activeCalls_;
594 0 : if (activeCalls_ == 0) {
595 0 : passive_.set();
596 0 : }
597 0 : }
598 :
599 0 : bool Bridge::makeCall(
600 : OUString const & oid, css::uno::TypeDescription const & member,
601 : bool setter, std::vector< BinaryAny > const & inArguments,
602 : BinaryAny * returnValue, std::vector< BinaryAny > * outArguments)
603 : {
604 0 : std::auto_ptr< IncomingReply > resp;
605 : {
606 0 : uno_ThreadPool tp = getThreadPool();
607 0 : AttachThread att(tp);
608 : PopOutgoingRequest pop(
609 : outgoingRequests_, att.getTid(),
610 0 : OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
611 : sendRequest(
612 : att.getTid(), oid, css::uno::TypeDescription(), member,
613 0 : inArguments);
614 0 : pop.clear();
615 0 : incrementCalls(true);
616 0 : incrementActiveCalls();
617 : void * job;
618 0 : uno_threadpool_enter(tp, &job);
619 0 : resp.reset(static_cast< IncomingReply * >(job));
620 0 : decrementActiveCalls();
621 0 : decrementCalls();
622 : }
623 0 : if (resp.get() == 0) {
624 : throw css::lang::DisposedException(
625 : "Binary URP bridge disposed during call",
626 0 : static_cast< cppu::OWeakObject * >(this));
627 : }
628 0 : *returnValue = resp->returnValue;
629 0 : if (!resp->exception) {
630 0 : *outArguments = resp->outArguments;
631 : }
632 0 : return resp->exception;
633 : }
634 :
635 0 : void Bridge::sendRequestChangeRequest() {
636 : assert(mode_ == MODE_REQUESTED);
637 0 : random_ = random();
638 0 : std::vector< BinaryAny > a;
639 : a.push_back(
640 : BinaryAny(
641 0 : css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
642 0 : &random_));
643 0 : sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
644 0 : }
645 :
646 0 : void Bridge::handleRequestChangeReply(
647 : bool exception, BinaryAny const & returnValue)
648 : {
649 : try {
650 0 : throwException(exception, returnValue);
651 0 : } catch (css::uno::RuntimeException & e) {
652 : // Before OOo 2.2, Java URP would throw a RuntimeException when
653 : // receiving a requestChange message (see i#35277 "Java URP: Support
654 : // Manipulation of Protocol Properties"):
655 0 : if (mode_ != MODE_REQUESTED) {
656 0 : throw;
657 : }
658 : SAL_WARN(
659 : "binaryurp",
660 : "requestChange caught RuntimeException \'" << e.Message
661 : << "' in state 'requested'");
662 0 : mode_ = MODE_NORMAL;
663 0 : getWriter()->unblock();
664 0 : decrementCalls();
665 0 : return;
666 : }
667 : sal_Int32 n = *static_cast< sal_Int32 * >(
668 : returnValue.getValue(
669 0 : css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
670 0 : sal_Int32 exp = 0;
671 0 : switch (mode_) {
672 : case MODE_REQUESTED:
673 : case MODE_REPLY_1:
674 0 : exp = 1;
675 0 : break;
676 : case MODE_REPLY_MINUS1:
677 0 : exp = -1;
678 0 : mode_ = MODE_REQUESTED;
679 0 : break;
680 : case MODE_REPLY_0:
681 0 : exp = 0;
682 0 : mode_ = MODE_WAIT;
683 0 : break;
684 : default:
685 : assert(false); // this cannot happen
686 0 : break;
687 : }
688 0 : if (n != exp) {
689 : throw css::uno::RuntimeException(
690 : "URP: requestChange reply with unexpected return value received",
691 0 : static_cast< cppu::OWeakObject * >(this));
692 : }
693 0 : decrementCalls();
694 0 : switch (exp) {
695 : case -1:
696 0 : sendRequestChangeRequest();
697 0 : break;
698 : case 0:
699 0 : break;
700 : case 1:
701 0 : sendCommitChangeRequest();
702 0 : break;
703 : default:
704 : assert(false); // this cannot happen
705 0 : break;
706 : }
707 : }
708 :
709 0 : void Bridge::handleCommitChangeReply(
710 : bool exception, BinaryAny const & returnValue)
711 : {
712 0 : bool ccMode = true;
713 : try {
714 0 : throwException(exception, returnValue);
715 0 : } catch (const css::bridge::InvalidProtocolChangeException &) {
716 0 : ccMode = false;
717 : }
718 0 : if (ccMode) {
719 0 : setCurrentContextMode();
720 : }
721 : assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
722 0 : mode_ = MODE_NORMAL;
723 0 : getWriter()->unblock();
724 0 : decrementCalls();
725 0 : }
726 :
727 0 : void Bridge::handleRequestChangeRequest(
728 : rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
729 : {
730 : assert(inArguments.size() == 1);
731 0 : switch (mode_) {
732 : case MODE_REQUESTED:
733 : {
734 : sal_Int32 n2 = *static_cast< sal_Int32 * >(
735 0 : inArguments[0].getValue(
736 : css::uno::TypeDescription(
737 0 : cppu::UnoType< sal_Int32 >::get())));
738 : sal_Int32 ret;
739 0 : if (n2 > random_) {
740 0 : ret = 1;
741 0 : mode_ = MODE_REPLY_0;
742 0 : } else if (n2 == random_) {
743 0 : ret = -1;
744 0 : mode_ = MODE_REPLY_MINUS1;
745 : } else {
746 0 : ret = 0;
747 0 : mode_ = MODE_REPLY_1;
748 : }
749 : getWriter()->sendDirectReply(
750 : tid, protPropRequest_, false,
751 : BinaryAny(
752 : css::uno::TypeDescription(
753 0 : cppu::UnoType< sal_Int32 >::get()),
754 : &ret),
755 0 : std::vector< BinaryAny >());
756 : break;
757 : }
758 : case MODE_NORMAL:
759 : {
760 0 : mode_ = MODE_NORMAL_WAIT;
761 0 : sal_Int32 ret = 1;
762 : getWriter()->queueReply(
763 : tid, protPropRequest_, false, false,
764 : BinaryAny(
765 : css::uno::TypeDescription(
766 0 : cppu::UnoType< sal_Int32 >::get()),
767 : &ret),
768 0 : std::vector< BinaryAny >(), false);
769 : break;
770 : }
771 : default:
772 : throw css::uno::RuntimeException(
773 : "URP: unexpected requestChange request received",
774 0 : static_cast< cppu::OWeakObject * >(this));
775 : }
776 0 : }
777 :
778 0 : void Bridge::handleCommitChangeRequest(
779 : rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
780 : {
781 0 : bool ccMode = false;
782 0 : bool exc = false;
783 0 : BinaryAny ret;
784 : assert(inArguments.size() == 1);
785 0 : css::uno::Sequence< css::bridge::ProtocolProperty > s;
786 0 : bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
787 : assert(ok);
788 : (void) ok; // avoid warnings
789 0 : for (sal_Int32 i = 0; i != s.getLength(); ++i) {
790 0 : if (s[i].Name == "CurrentContext") {
791 0 : ccMode = true;
792 : } else {
793 0 : ccMode = false;
794 0 : exc = true;
795 : ret = mapCppToBinaryAny(
796 : css::uno::makeAny(
797 : css::bridge::InvalidProtocolChangeException(
798 : "InvalidProtocolChangeException",
799 0 : css::uno::Reference< css::uno::XInterface >(), s[i],
800 0 : 1)));
801 0 : break;
802 : }
803 : }
804 0 : switch (mode_) {
805 : case MODE_WAIT:
806 : getWriter()->sendDirectReply(
807 0 : tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
808 0 : if (ccMode) {
809 0 : setCurrentContextMode();
810 0 : mode_ = MODE_NORMAL;
811 0 : getWriter()->unblock();
812 : } else {
813 0 : mode_ = MODE_REQUESTED;
814 0 : sendRequestChangeRequest();
815 : }
816 0 : break;
817 : case MODE_NORMAL_WAIT:
818 : getWriter()->queueReply(
819 : tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(),
820 0 : ccMode);
821 0 : mode_ = MODE_NORMAL;
822 0 : break;
823 : default:
824 : throw css::uno::RuntimeException(
825 : "URP: unexpected commitChange request received",
826 0 : static_cast< cppu::OWeakObject * >(this));
827 0 : }
828 0 : }
829 :
830 0 : OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
831 0 : OutgoingRequest req(outgoingRequests_.top(tid));
832 0 : outgoingRequests_.pop(tid);
833 0 : return req;
834 : }
835 :
836 0 : bool Bridge::isProtocolPropertiesRequest(
837 : OUString const & oid, css::uno::TypeDescription const & type) const
838 : {
839 0 : return oid == protPropOid_ && type.equals(protPropType_);
840 : }
841 :
842 0 : void Bridge::setCurrentContextMode() {
843 0 : osl::MutexGuard g(mutex_);
844 0 : currentContextMode_ = true;
845 0 : }
846 :
847 0 : bool Bridge::isCurrentContextMode() {
848 0 : osl::MutexGuard g(mutex_);
849 0 : return currentContextMode_;
850 : }
851 :
852 0 : Bridge::~Bridge() {
853 : #if OSL_DEBUG_LEVEL > 0
854 : {
855 : osl::MutexGuard g(mutex_);
856 : SAL_WARN_IF(
857 : state_ == STATE_STARTED || state_ == STATE_TERMINATED, "binaryurp",
858 : "undisposed bridge, potential deadlock ahead");
859 : }
860 : #endif
861 0 : dispose();
862 0 : }
863 :
864 0 : css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
865 : OUString const & sInstanceName) throw (css::uno::RuntimeException)
866 : {
867 0 : if (sInstanceName.isEmpty()) {
868 : throw css::uno::RuntimeException(
869 : "XBridge::getInstance sInstanceName must be non-empty",
870 0 : static_cast< cppu::OWeakObject * >(this));
871 : }
872 0 : for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
873 0 : if (sInstanceName[i] > 0x7F) {
874 : throw css::io::IOException(
875 : ("XBridge::getInstance sInstanceName contains non-ASCII"
876 : " character"),
877 0 : css::uno::Reference< css::uno::XInterface >());
878 : }
879 : }
880 : css::uno::TypeDescription ifc(
881 0 : cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get());
882 0 : typelib_TypeDescription * p = ifc.get();
883 0 : std::vector< BinaryAny > inArgs;
884 : inArgs.push_back(
885 : BinaryAny(
886 0 : css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
887 0 : &p));
888 0 : BinaryAny ret;
889 0 : std::vector< BinaryAny> outArgs;
890 : bool exc = makeCall(
891 : sInstanceName,
892 : css::uno::TypeDescription(
893 : "com.sun.star.uno.XInterface::queryInterface"),
894 0 : false, inArgs, &ret, &outArgs);
895 0 : throwException(exc, ret);
896 : return css::uno::Reference< css::uno::XInterface >(
897 : static_cast< css::uno::XInterface * >(
898 : binaryToCppMapping_.mapInterface(
899 0 : *static_cast< uno_Interface ** >(ret.getValue(ifc)),
900 0 : ifc.get())),
901 0 : css::uno::UNO_REF_NO_ACQUIRE);
902 : }
903 :
904 0 : OUString Bridge::getName() throw (css::uno::RuntimeException) {
905 0 : return name_;
906 : }
907 :
908 0 : OUString Bridge::getDescription() throw (css::uno::RuntimeException) {
909 0 : OUStringBuffer b(name_);
910 0 : b.append(sal_Unicode(':'));
911 0 : b.append(connection_->getDescription());
912 0 : return b.makeStringAndClear();
913 : }
914 :
915 0 : void Bridge::dispose() throw (css::uno::RuntimeException) {
916 : // For terminate(true) not to deadlock, an external protocol must ensure
917 : // that dispose is not called from a thread pool worker thread (that dispose
918 : // is never called from the reader or writer thread is already ensured
919 : // internally):
920 0 : terminate(true);
921 : // OOo expects dispose to not return while there are still remote calls in
922 : // progress; an external protocol must ensure that dispose is not called
923 : // from within an incoming or outgoing remote call, as passive_.wait() would
924 : // otherwise deadlock:
925 0 : passive_.wait();
926 0 : }
927 :
928 0 : void Bridge::addEventListener(
929 : css::uno::Reference< css::lang::XEventListener > const & xListener)
930 : throw (css::uno::RuntimeException)
931 : {
932 : assert(xListener.is());
933 : {
934 0 : osl::MutexGuard g(mutex_);
935 : assert(state_ != STATE_INITIAL);
936 0 : if (state_ == STATE_STARTED) {
937 0 : listeners_.push_back(xListener);
938 0 : return;
939 0 : }
940 : }
941 0 : xListener->disposing(
942 0 : css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
943 : }
944 :
945 0 : void Bridge::removeEventListener(
946 : css::uno::Reference< css::lang::XEventListener > const & aListener)
947 : throw (css::uno::RuntimeException)
948 : {
949 0 : osl::MutexGuard g(mutex_);
950 : Listeners::iterator i(
951 0 : std::find(listeners_.begin(), listeners_.end(), aListener));
952 0 : if (i != listeners_.end()) {
953 0 : listeners_.erase(i);
954 0 : }
955 0 : }
956 :
957 0 : void Bridge::sendCommitChangeRequest() {
958 : assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
959 0 : css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
960 0 : s[0].Name = "CurrentContext";
961 0 : std::vector< BinaryAny > a;
962 0 : a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
963 0 : sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
964 0 : }
965 :
966 0 : void Bridge::sendProtPropRequest(
967 : OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments)
968 : {
969 : assert(
970 : kind == OutgoingRequest::KIND_REQUEST_CHANGE ||
971 : kind == OutgoingRequest::KIND_COMMIT_CHANGE);
972 0 : incrementCalls(false);
973 : css::uno::TypeDescription member(
974 : kind == OutgoingRequest::KIND_REQUEST_CHANGE
975 0 : ? protPropRequest_ : protPropCommit_);
976 : PopOutgoingRequest pop(
977 0 : outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
978 : getWriter()->sendDirectRequest(
979 0 : protPropTid_, protPropOid_, protPropType_, member, inArguments);
980 0 : pop.clear();
981 0 : }
982 :
983 0 : void Bridge::makeReleaseCall(
984 : OUString const & oid, css::uno::TypeDescription const & type)
985 : {
986 0 : AttachThread att(getThreadPool());
987 : sendRequest(
988 : att.getTid(), oid, type,
989 : css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
990 0 : std::vector< BinaryAny >());
991 0 : }
992 :
993 0 : void Bridge::sendRequest(
994 : rtl::ByteSequence const & tid, OUString const & oid,
995 : css::uno::TypeDescription const & type,
996 : css::uno::TypeDescription const & member,
997 : std::vector< BinaryAny > const & inArguments)
998 : {
999 0 : getWriter()->queueRequest(tid, oid, type, member, inArguments);
1000 0 : }
1001 :
1002 0 : void Bridge::throwException(bool exception, BinaryAny const & value) {
1003 0 : if (exception) {
1004 0 : cppu::throwException(mapBinaryToCppAny(value));
1005 : }
1006 0 : }
1007 :
1008 0 : css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
1009 0 : BinaryAny in(binaryAny);
1010 0 : css::uno::Any out;
1011 0 : out.~Any();
1012 : uno_copyAndConvertData(
1013 0 : &out, in.get(),
1014 0 : css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
1015 0 : binaryToCppMapping_.get());
1016 0 : return out;
1017 : }
1018 :
1019 0 : bool Bridge::becameUnused() const {
1020 0 : return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
1021 : }
1022 :
1023 0 : void Bridge::terminateWhenUnused(bool unused) {
1024 0 : if (unused) {
1025 : // That the current thread considers the bridge unused implies that it
1026 : // is not within an incoming or outgoing remote call (so calling
1027 : // terminate cannot lead to deadlock):
1028 0 : terminate(false);
1029 : }
1030 0 : }
1031 :
1032 0 : void Bridge::checkDisposed() {
1033 : assert(state_ != STATE_INITIAL);
1034 0 : if (state_ != STATE_STARTED) {
1035 : throw css::lang::DisposedException(
1036 : "Binary URP bridge already disposed",
1037 0 : static_cast< cppu::OWeakObject * >(this));
1038 : }
1039 0 : }
1040 :
1041 : }
1042 :
1043 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|