1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 #include "sal/config.h"
25
26 #include <algorithm>
27 #include <cstddef>
28 #include <limits>
29 #include <memory>
30 #include <vector>
31
32 #include "boost/noncopyable.hpp"
33 #include "com/sun/star/bridge/InvalidProtocolChangeException.hpp"
34 #include "com/sun/star/bridge/XBridge.hpp"
35 #include "com/sun/star/bridge/XInstanceProvider.hpp"
36 #include "com/sun/star/bridge/XProtocolProperties.hpp"
37 #include "com/sun/star/connection/XConnection.hpp"
38 #include "com/sun/star/io/IOException.hpp"
39 #include "com/sun/star/lang/DisposedException.hpp"
40 #include "com/sun/star/lang/EventObject.hpp"
41 #include "com/sun/star/lang/XEventListener.hpp"
42 #include "com/sun/star/uno/Reference.hxx"
43 #include "com/sun/star/uno/RuntimeException.hpp"
44 #include "com/sun/star/uno/Sequence.hxx"
45 #include "com/sun/star/uno/XInterface.hpp"
46 #include "cppuhelper/exc_hlp.hxx"
47 #include "cppuhelper/weak.hxx"
48 #include "osl/diagnose.h"
49 #include "osl/mutex.hxx"
50 #include "osl/thread.hxx"
51 #include "rtl/byteseq.hxx"
52 #include "rtl/random.h"
53 #include "rtl/ref.hxx"
54 #include "rtl/textenc.h"
55 #include "rtl/ustrbuf.hxx"
56 #include "rtl/ustring.h"
57 #include "rtl/ustring.hxx"
58 #include "sal/types.h"
59 #include "typelib/typeclass.h"
60 #include "typelib/typedescription.h"
61 #include "typelib/typedescription.hxx"
62 #include "uno/dispatcher.hxx"
63 #include "uno/environment.hxx"
64 #include "uno/lbnames.h"
65
66 #include "binaryany.hxx"
67 #include "bridge.hxx"
68 #include "bridgefactory.hxx"
69 #include "incomingreply.hxx"
70 #include "lessoperators.hxx"
71 #include "outgoingrequest.hxx"
72 #include "outgoingrequests.hxx"
73 #include "proxy.hxx"
74 #include "reader.hxx"
75
76 namespace binaryurp {
77
78 namespace {
79
80 namespace css = com::sun::star;
81
random()82 sal_Int32 random() {
83 sal_Int32 n;
84 rtlRandomPool pool = rtl_random_createPool();
85 rtl_random_getBytes(pool, &n, sizeof n);
86 rtl_random_destroyPool(pool);
87 return n;
88 }
89
freeProxyCallback(uno_ExtEnvironment *,void * pProxy)90 extern "C" void SAL_CALL freeProxyCallback(uno_ExtEnvironment *, void * pProxy)
91 {
92 OSL_ASSERT(pProxy != 0);
93 static_cast< Proxy * >(pProxy)->do_free();
94 }
95
joinThread(osl::Thread * thread)96 void joinThread(osl::Thread * thread) {
97 OSL_ASSERT(thread != 0);
98 if (thread->getIdentifier() != osl::Thread::getCurrentIdentifier()) {
99 thread->join();
100 }
101 }
102
103 class AttachThread: private boost::noncopyable {
104 public:
105 explicit AttachThread(uno_ThreadPool threadPool);
106
107 ~AttachThread();
108
109 rtl::ByteSequence getTid() throw ();
110
111 private:
112 uno_ThreadPool threadPool_;
113 rtl::ByteSequence tid_;
114 };
115
AttachThread(uno_ThreadPool threadPool)116 AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
117 sal_Sequence * s = 0;
118 uno_getIdOfCurrentThread(&s);
119 tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
120 uno_threadpool_attach(threadPool_);
121 }
122
~AttachThread()123 AttachThread::~AttachThread() {
124 uno_threadpool_detach(threadPool_);
125 uno_releaseIdFromCurrentThread();
126 }
127
getTid()128 rtl::ByteSequence AttachThread::getTid() throw () {
129 return tid_;
130 }
131
132 class PopOutgoingRequest: private boost::noncopyable {
133 public:
134 PopOutgoingRequest(
135 OutgoingRequests & requests, rtl::ByteSequence const & tid,
136 OutgoingRequest const & request);
137
138 ~PopOutgoingRequest();
139
140 void clear();
141
142 private:
143 OutgoingRequests & requests_;
144 rtl::ByteSequence tid_;
145 bool cleared_;
146 };
147
PopOutgoingRequest(OutgoingRequests & requests,rtl::ByteSequence const & tid,OutgoingRequest const & request)148 PopOutgoingRequest::PopOutgoingRequest(
149 OutgoingRequests & requests, rtl::ByteSequence const & tid,
150 OutgoingRequest const & request):
151 requests_(requests), tid_(tid), cleared_(false)
152 {
153 requests_.push(tid_, request);
154 }
155
~PopOutgoingRequest()156 PopOutgoingRequest::~PopOutgoingRequest() {
157 if (!cleared_) {
158 requests_.pop(tid_);
159 }
160 }
161
clear()162 void PopOutgoingRequest::clear() {
163 cleared_ = true;
164 }
165
166 }
167
Bridge(rtl::Reference<BridgeFactory> const & factory,rtl::OUString const & name,css::uno::Reference<css::connection::XConnection> const & connection,css::uno::Reference<css::bridge::XInstanceProvider> const & provider)168 Bridge::Bridge(
169 rtl::Reference< BridgeFactory > const & factory, rtl::OUString const & name,
170 css::uno::Reference< css::connection::XConnection > const & connection,
171 css::uno::Reference< css::bridge::XInstanceProvider > const & provider):
172 factory_(factory), name_(name), connection_(connection),
173 provider_(provider),
174 binaryUno_(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO))),
175 cppToBinaryMapping_(
176 rtl::OUString(
177 RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME)),
178 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO))),
179 binaryToCppMapping_(
180 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO)),
181 rtl::OUString(
182 RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME))),
183 protPropTid_(
184 reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"),
185 RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
186 protPropOid_(RTL_CONSTASCII_USTRINGPARAM("UrpProtocolProperties")),
187 protPropType_(
188 cppu::UnoType<
189 css::uno::Reference< css::bridge::XProtocolProperties > >::get()),
190 protPropRequest_(
191 rtl::OUString(
192 RTL_CONSTASCII_USTRINGPARAM(
193 "com.sun.star.bridge.XProtocolProperties::requestChange"))),
194 protPropCommit_(
195 rtl::OUString(
196 RTL_CONSTASCII_USTRINGPARAM(
197 "com.sun.star.bridge.XProtocolProperties::commitChange"))),
198 threadPool_(0), currentContextMode_(false), proxies_(0), calls_(0),
199 normalCall_(false), activeCalls_(0), terminated_(false),
200 mode_(MODE_REQUESTED)
201 {
202 OSL_ASSERT(factory.is() && connection.is());
203 if (!binaryUno_.is()) {
204 throw css::uno::RuntimeException(
205 rtl::OUString(
206 RTL_CONSTASCII_USTRINGPARAM("URP: no binary UNO environment")),
207 css::uno::Reference< css::uno::XInterface >());
208 }
209 if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) {
210 throw css::uno::RuntimeException(
211 rtl::OUString(
212 RTL_CONSTASCII_USTRINGPARAM("URP: no C++ UNO mapping")),
213 css::uno::Reference< css::uno::XInterface >());
214 }
215 passive_.set();
216 }
217
start()218 void Bridge::start() {
219 OSL_ASSERT(threadPool_ == 0 && !writer_.is() && !reader_.is());
220 threadPool_ = uno_threadpool_create();
221 OSL_ASSERT(threadPool_ != 0);
222 writer_.set(new Writer(this));
223 writer_->create();
224 reader_.set(new Reader(this));
225 reader_->create();
226 }
227
terminate()228 void Bridge::terminate() {
229 rtl::Reference< Reader > r;
230 rtl::Reference< Writer > w;
231 Listeners ls;
232 {
233 osl::MutexGuard g(mutex_);
234 if (terminated_) {
235 return;
236 }
237 std::swap(reader_, r);
238 std::swap(writer_, w);
239 ls.swap(listeners_);
240 terminated_ = true;
241 }
242 try {
243 connection_->close();
244 } catch (css::io::IOException & e) {
245 OSL_TRACE(
246 OSL_LOG_PREFIX "caught IO exception '%s'",
247 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
248 }
249 OSL_ASSERT(w.is());
250 w->stop();
251 joinThread(r.get());
252 joinThread(w.get());
253 OSL_ASSERT(threadPool_ != 0);
254 uno_threadpool_dispose(threadPool_);
255 Stubs s;
256 {
257 osl::MutexGuard g(mutex_);
258 s.swap(stubs_);
259 }
260 for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
261 for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j) {
262 binaryUno_.get()->pExtEnv->revokeInterface(
263 binaryUno_.get()->pExtEnv, j->second.object.get());
264 }
265 }
266 factory_->removeBridge(this);
267 for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
268 try {
269 (*i)->disposing(
270 css::lang::EventObject(
271 static_cast< cppu::OWeakObject * >(this)));
272 } catch (css::uno::RuntimeException & e) {
273 OSL_TRACE(
274 OSL_LOG_PREFIX "caught runtime exception '%s'",
275 rtl::OUStringToOString(
276 e.Message, RTL_TEXTENCODING_UTF8).getStr());
277 }
278 }
279 }
280
getConnection() const281 css::uno::Reference< css::connection::XConnection > Bridge::getConnection()
282 const
283 {
284 return connection_;
285 }
286
getProvider() const287 css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider()
288 const
289 {
290 return provider_;
291 }
292
getCppToBinaryMapping()293 css::uno::Mapping & Bridge::getCppToBinaryMapping() {
294 return cppToBinaryMapping_;
295 }
296
mapCppToBinaryAny(css::uno::Any const & cppAny)297 BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
298 css::uno::Any in(cppAny);
299 BinaryAny out;
300 out.~BinaryAny();
301 uno_copyAndConvertData(
302 out.get(), &in,
303 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
304 cppToBinaryMapping_.get());
305 return out;
306 }
307
getThreadPool() const308 uno_ThreadPool Bridge::getThreadPool() const {
309 OSL_ASSERT(threadPool_ != 0);
310 return threadPool_;
311 }
312
getWriter()313 rtl::Reference< Writer > Bridge::getWriter() {
314 osl::MutexGuard g(mutex_);
315 if (terminated_) {
316 throw css::lang::DisposedException(
317 rtl::OUString(
318 RTL_CONSTASCII_USTRINGPARAM(
319 "Binary URP bridge already disposed")),
320 static_cast< cppu::OWeakObject * >(this));
321 }
322 OSL_ASSERT(writer_.is());
323 return writer_;
324 }
325
registerIncomingInterface(rtl::OUString const & oid,css::uno::TypeDescription const & type)326 css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
327 rtl::OUString const & oid, css::uno::TypeDescription const & type)
328 {
329 OSL_ASSERT(type.is());
330 if ( oid.isEmpty() ) {
331 return css::uno::UnoInterfaceReference();
332 }
333 css::uno::UnoInterfaceReference obj(findStub(oid, type));
334 if (!obj.is()) {
335 binaryUno_.get()->pExtEnv->getRegisteredInterface(
336 binaryUno_.get()->pExtEnv,
337 reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
338 reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
339 if (obj.is()) {
340 makeReleaseCall(oid, type);
341 } else {
342 obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
343 {
344 osl::MutexGuard g(mutex_);
345 OSL_ASSERT(
346 proxies_ < std::numeric_limits< std::size_t >::max());
347 ++proxies_;
348 }
349 binaryUno_.get()->pExtEnv->registerProxyInterface(
350 binaryUno_.get()->pExtEnv,
351 reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
352 oid.pData,
353 reinterpret_cast< typelib_InterfaceTypeDescription * >(
354 type.get()));
355 }
356 }
357 return obj;
358 }
359
registerOutgoingInterface(css::uno::UnoInterfaceReference const & object,css::uno::TypeDescription const & type)360 rtl::OUString Bridge::registerOutgoingInterface(
361 css::uno::UnoInterfaceReference const & object,
362 css::uno::TypeDescription const & type)
363 {
364 OSL_ASSERT(type.is());
365 if (!object.is()) {
366 return rtl::OUString();
367 }
368 rtl::OUString oid;
369 if (!Proxy::isProxy(this, object, &oid)) {
370 binaryUno_.get()->pExtEnv->getObjectIdentifier(
371 binaryUno_.get()->pExtEnv, &oid.pData, object.get());
372 osl::MutexGuard g(mutex_);
373 Stubs::iterator i(stubs_.find(oid));
374 Stub newStub;
375 Stub * stub = i == stubs_.end() ? &newStub : &i->second;
376 Stub::iterator j(stub->find(type));
377 //TODO: Release sub-stub if it is not successfully sent to remote side
378 // (otherwise, stub will leak until terminate()):
379 if (j == stub->end()) {
380 j = stub->insert(Stub::value_type(type, SubStub())).first;
381 if (stub == &newStub) {
382 i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
383 std::swap(i->second, newStub);
384 j = i->second.find(type);
385 OSL_ASSERT(j != i->second.end());
386 }
387 j->second.object = object;
388 j->second.references = 1;
389 binaryUno_.get()->pExtEnv->registerInterface(
390 binaryUno_.get()->pExtEnv,
391 reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
392 oid.pData,
393 reinterpret_cast< typelib_InterfaceTypeDescription * >(
394 type.get()));
395 } else {
396 OSL_ASSERT(stub != &newStub);
397 if (j->second.references == SAL_MAX_UINT32) {
398 throw css::uno::RuntimeException(
399 rtl::OUString(
400 RTL_CONSTASCII_USTRINGPARAM(
401 "URP: stub reference count overflow")),
402 css::uno::Reference< css::uno::XInterface >());
403 }
404 ++j->second.references;
405 }
406 }
407 return oid;
408 }
409
findStub(rtl::OUString const & oid,css::uno::TypeDescription const & type)410 css::uno::UnoInterfaceReference Bridge::findStub(
411 rtl::OUString const & oid, css::uno::TypeDescription const & type)
412 {
413 OSL_ASSERT(!oid.isEmpty() && type.is());
414 osl::MutexGuard g(mutex_);
415 Stubs::iterator i(stubs_.find(oid));
416 if (i != stubs_.end()) {
417 Stub::iterator j(i->second.find(type));
418 if (j != i->second.end()) {
419 return j->second.object;
420 }
421 for (j = i->second.begin(); j != i->second.end(); ++j) {
422 if (typelib_typedescription_isAssignableFrom(
423 type.get(), j->first.get()))
424 {
425 return j->second.object;
426 }
427 }
428 }
429 return css::uno::UnoInterfaceReference();
430 }
431
releaseStub(rtl::OUString const & oid,css::uno::TypeDescription const & type)432 void Bridge::releaseStub(
433 rtl::OUString const & oid, css::uno::TypeDescription const & type)
434 {
435 OSL_ASSERT(!oid.isEmpty() && type.is());
436 css::uno::UnoInterfaceReference obj;
437 bool unused;
438 {
439 osl::MutexGuard g(mutex_);
440 Stubs::iterator i(stubs_.find(oid));
441 if (i == stubs_.end()) {
442 throw css::uno::RuntimeException(
443 rtl::OUString(
444 RTL_CONSTASCII_USTRINGPARAM("URP: release unknown stub")),
445 css::uno::Reference< css::uno::XInterface >());
446 }
447 Stub::iterator j(i->second.find(type));
448 if (j == i->second.end()) {
449 throw css::uno::RuntimeException(
450 rtl::OUString(
451 RTL_CONSTASCII_USTRINGPARAM("URP: release unknown stub")),
452 css::uno::Reference< css::uno::XInterface >());
453 }
454 OSL_ASSERT(j->second.references > 0);
455 --j->second.references;
456 if (j->second.references == 0) {
457 obj = j->second.object;
458 i->second.erase(j);
459 if (i->second.empty()) {
460 stubs_.erase(i);
461 }
462 }
463 unused = becameUnused();
464 }
465 if (obj.is()) {
466 binaryUno_.get()->pExtEnv->revokeInterface(
467 binaryUno_.get()->pExtEnv, obj.get());
468 }
469 terminateWhenUnused(unused);
470 }
471
resurrectProxy(Proxy & proxy)472 void Bridge::resurrectProxy(Proxy & proxy) {
473 uno_Interface * p = &proxy;
474 binaryUno_.get()->pExtEnv->registerProxyInterface(
475 binaryUno_.get()->pExtEnv,
476 reinterpret_cast< void ** >(&p), &freeProxyCallback,
477 proxy.getOid().pData,
478 reinterpret_cast< typelib_InterfaceTypeDescription * >(
479 proxy.getType().get()));
480 OSL_ASSERT(p == &proxy);
481 }
482
revokeProxy(Proxy & proxy)483 void Bridge::revokeProxy(Proxy & proxy) {
484 binaryUno_.get()->pExtEnv->revokeInterface(
485 binaryUno_.get()->pExtEnv, &proxy);
486 }
487
freeProxy(Proxy & proxy)488 void Bridge::freeProxy(Proxy & proxy) {
489 try {
490 makeReleaseCall(proxy.getOid(), proxy.getType());
491 } catch (css::uno::RuntimeException & e) {
492 OSL_TRACE(
493 OSL_LOG_PREFIX "caught runtime exception '%s'",
494 rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
495 } catch (std::exception & e) {
496 OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
497 }
498 bool unused;
499 {
500 osl::MutexGuard g(mutex_);
501 OSL_ASSERT(proxies_ > 0);
502 --proxies_;
503 unused = becameUnused();
504 }
505 terminateWhenUnused(unused);
506 }
507
incrementCalls(bool normalCall)508 void Bridge::incrementCalls(bool normalCall) throw () {
509 osl::MutexGuard g(mutex_);
510 OSL_ASSERT(calls_ < std::numeric_limits< std::size_t >::max());
511 ++calls_;
512 normalCall_ |= normalCall;
513 }
514
decrementCalls()515 void Bridge::decrementCalls() {
516 bool unused;
517 {
518 osl::MutexGuard g(mutex_);
519 OSL_ASSERT(calls_ > 0);
520 --calls_;
521 unused = becameUnused();
522 }
523 terminateWhenUnused(unused);
524 }
525
incrementActiveCalls()526 void Bridge::incrementActiveCalls() throw () {
527 osl::MutexGuard g(mutex_);
528 OSL_ASSERT(
529 activeCalls_ <= calls_ &&
530 activeCalls_ < std::numeric_limits< std::size_t >::max());
531 ++activeCalls_;
532 passive_.reset();
533 }
534
decrementActiveCalls()535 void Bridge::decrementActiveCalls() throw () {
536 osl::MutexGuard g(mutex_);
537 OSL_ASSERT(activeCalls_ <= calls_ && activeCalls_ > 0);
538 --activeCalls_;
539 if (activeCalls_ == 0) {
540 passive_.set();
541 }
542 }
543
makeCall(rtl::OUString const & oid,css::uno::TypeDescription const & member,bool setter,std::vector<BinaryAny> const & inArguments,BinaryAny * returnValue,std::vector<BinaryAny> * outArguments)544 bool Bridge::makeCall(
545 rtl::OUString const & oid, css::uno::TypeDescription const & member,
546 bool setter, std::vector< BinaryAny > const & inArguments,
547 BinaryAny * returnValue, std::vector< BinaryAny > * outArguments)
548 {
549 std::auto_ptr< IncomingReply > resp;
550 {
551 AttachThread att(threadPool_);
552 PopOutgoingRequest pop(
553 outgoingRequests_, att.getTid(),
554 OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
555 sendRequest(
556 att.getTid(), oid, css::uno::TypeDescription(), member,
557 inArguments);
558 pop.clear();
559 incrementCalls(true);
560 incrementActiveCalls();
561 void * job;
562 uno_threadpool_enter(threadPool_, &job);
563 resp.reset(static_cast< IncomingReply * >(job));
564 decrementActiveCalls();
565 decrementCalls();
566 }
567 if (resp.get() == 0) {
568 throw css::lang::DisposedException(
569 rtl::OUString(
570 RTL_CONSTASCII_USTRINGPARAM(
571 "Binary URP bridge disposed during call")),
572 static_cast< cppu::OWeakObject * >(this));
573 }
574 *returnValue = resp->returnValue;
575 if (!resp->exception) {
576 *outArguments = resp->outArguments;
577 }
578 return resp->exception;
579 }
580
sendRequestChangeRequest()581 void Bridge::sendRequestChangeRequest() {
582 OSL_ASSERT(mode_ == MODE_REQUESTED);
583 random_ = random();
584 std::vector< BinaryAny > a;
585 a.push_back(
586 BinaryAny(
587 css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
588 &random_));
589 sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
590 }
591
handleRequestChangeReply(bool exception,BinaryAny const & returnValue)592 void Bridge::handleRequestChangeReply(
593 bool exception, BinaryAny const & returnValue)
594 {
595 throwException(exception, returnValue);
596 sal_Int32 n = *static_cast< sal_Int32 * >(
597 returnValue.getValue(
598 css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
599 sal_Int32 exp = 0;
600 switch (mode_) {
601 case MODE_REQUESTED:
602 case MODE_REPLY_1:
603 exp = 1;
604 break;
605 case MODE_REPLY_MINUS1:
606 exp = -1;
607 mode_ = MODE_REQUESTED;
608 break;
609 case MODE_REPLY_0:
610 exp = 0;
611 mode_ = MODE_WAIT;
612 break;
613 default:
614 OSL_ASSERT(false); // this cannot happen
615 break;
616 }
617 if (n != exp) {
618 throw css::uno::RuntimeException(
619 rtl::OUString(
620 RTL_CONSTASCII_USTRINGPARAM(
621 "URP: requestChange reply with unexpected return value"
622 " received")),
623 static_cast< cppu::OWeakObject * >(this));
624 }
625 decrementCalls();
626 switch (exp) {
627 case -1:
628 sendRequestChangeRequest();
629 break;
630 case 0:
631 break;
632 case 1:
633 sendCommitChangeRequest();
634 break;
635 default:
636 OSL_ASSERT(false); // this cannot happen
637 break;
638 }
639 }
640
handleCommitChangeReply(bool exception,BinaryAny const & returnValue)641 void Bridge::handleCommitChangeReply(
642 bool exception, BinaryAny const & returnValue)
643 {
644 bool ccMode = true;
645 try {
646 throwException(exception, returnValue);
647 } catch (css::bridge::InvalidProtocolChangeException &) {
648 ccMode = false;
649 }
650 if (ccMode) {
651 setCurrentContextMode();
652 }
653 OSL_ASSERT(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
654 mode_ = MODE_NORMAL;
655 getWriter()->unblock();
656 decrementCalls();
657 }
658
handleRequestChangeRequest(rtl::ByteSequence const & tid,std::vector<BinaryAny> const & inArguments)659 void Bridge::handleRequestChangeRequest(
660 rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
661 {
662 OSL_ASSERT(inArguments.size() == 1);
663 switch (mode_) {
664 case MODE_REQUESTED:
665 {
666 sal_Int32 n2 = *static_cast< sal_Int32 * >(
667 inArguments[0].getValue(
668 css::uno::TypeDescription(
669 cppu::UnoType< sal_Int32 >::get())));
670 sal_Int32 ret;
671 if (n2 > random_) {
672 ret = 1;
673 mode_ = MODE_REPLY_0;
674 } else if (n2 == random_) {
675 ret = -1;
676 mode_ = MODE_REPLY_MINUS1;
677 } else {
678 ret = 0;
679 mode_ = MODE_REPLY_1;
680 }
681 getWriter()->sendDirectReply(
682 tid, protPropRequest_, false,
683 BinaryAny(
684 css::uno::TypeDescription(
685 cppu::UnoType< sal_Int32 >::get()),
686 &ret),
687 std::vector< BinaryAny >());
688 break;
689 }
690 case MODE_NORMAL:
691 {
692 mode_ = MODE_NORMAL_WAIT;
693 sal_Int32 ret = 1;
694 getWriter()->queueReply(
695 tid, protPropRequest_, false, false,
696 BinaryAny(
697 css::uno::TypeDescription(
698 cppu::UnoType< sal_Int32 >::get()),
699 &ret),
700 std::vector< BinaryAny >(), false);
701 break;
702 }
703 default:
704 throw css::uno::RuntimeException(
705 rtl::OUString(
706 RTL_CONSTASCII_USTRINGPARAM(
707 "URP: unexpected requestChange request received")),
708 static_cast< cppu::OWeakObject * >(this));
709 }
710 }
711
handleCommitChangeRequest(rtl::ByteSequence const & tid,std::vector<BinaryAny> const & inArguments)712 void Bridge::handleCommitChangeRequest(
713 rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
714 {
715 bool ccMode = false;
716 bool exc = false;
717 BinaryAny ret;
718 OSL_ASSERT(inArguments.size() == 1);
719 css::uno::Sequence< css::bridge::ProtocolProperty > s;
720 OSL_VERIFY(mapBinaryToCppAny(inArguments[0]) >>= s);
721 for (sal_Int32 i = 0; i != s.getLength(); ++i) {
722 if (s[i].Name.equalsAsciiL(
723 RTL_CONSTASCII_STRINGPARAM("CurrentContext")))
724 {
725 ccMode = true;
726 } else {
727 ccMode = false;
728 exc = true;
729 ret = mapCppToBinaryAny(
730 css::uno::makeAny(
731 css::bridge::InvalidProtocolChangeException(
732 rtl::OUString(
733 RTL_CONSTASCII_USTRINGPARAM(
734 "InvalidProtocolChangeException")),
735 css::uno::Reference< css::uno::XInterface >(), s[i],
736 1)));
737 break;
738 }
739 }
740 switch (mode_) {
741 case MODE_WAIT:
742 getWriter()->sendDirectReply(
743 tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
744 if (ccMode) {
745 setCurrentContextMode();
746 mode_ = MODE_NORMAL;
747 getWriter()->unblock();
748 } else {
749 mode_ = MODE_REQUESTED;
750 sendRequestChangeRequest();
751 }
752 break;
753 case MODE_NORMAL_WAIT:
754 getWriter()->queueReply(
755 tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(),
756 ccMode);
757 mode_ = MODE_NORMAL;
758 break;
759 default:
760 throw css::uno::RuntimeException(
761 rtl::OUString(
762 RTL_CONSTASCII_USTRINGPARAM(
763 "URP: unexpected commitChange request received")),
764 static_cast< cppu::OWeakObject * >(this));
765 }
766 }
767
lastOutgoingRequest(rtl::ByteSequence const & tid)768 OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
769 OutgoingRequest req(outgoingRequests_.top(tid));
770 outgoingRequests_.pop(tid);
771 return req;
772 }
773
isProtocolPropertiesRequest(rtl::OUString const & oid,css::uno::TypeDescription const & type) const774 bool Bridge::isProtocolPropertiesRequest(
775 rtl::OUString const & oid, css::uno::TypeDescription const & type) const
776 {
777 return oid == protPropOid_ && type.equals(protPropType_);
778 }
779
setCurrentContextMode()780 void Bridge::setCurrentContextMode() {
781 osl::MutexGuard g(mutex_);
782 currentContextMode_ = true;
783 }
784
isCurrentContextMode()785 bool Bridge::isCurrentContextMode() {
786 osl::MutexGuard g(mutex_);
787 return currentContextMode_;
788 }
789
~Bridge()790 Bridge::~Bridge() {
791 if (threadPool_ != 0) {
792 uno_threadpool_destroy(threadPool_);
793 }
794 }
795
getInstance(rtl::OUString const & sInstanceName)796 css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
797 rtl::OUString const & sInstanceName) throw (css::uno::RuntimeException)
798 {
799 if ( sInstanceName.isEmpty() ) {
800 throw css::uno::RuntimeException(
801 rtl::OUString(
802 RTL_CONSTASCII_USTRINGPARAM(
803 "XBridge::getInstance sInstanceName must be non-empty")),
804 static_cast< cppu::OWeakObject * >(this));
805 }
806 for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
807 if (sInstanceName[i] > 0x7F) {
808 throw css::io::IOException(
809 rtl::OUString(
810 RTL_CONSTASCII_USTRINGPARAM(
811 "XBridge::getInstance sInstanceName contains non-ASCII"
812 " character")),
813 css::uno::Reference< css::uno::XInterface >());
814 }
815 }
816 css::uno::TypeDescription ifc(
817 cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get());
818 typelib_TypeDescription * p = ifc.get();
819 std::vector< BinaryAny > inArgs;
820 inArgs.push_back(
821 BinaryAny(
822 css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
823 &p));
824 BinaryAny ret;
825 std::vector< BinaryAny> outArgs;
826 bool exc = makeCall(
827 sInstanceName,
828 css::uno::TypeDescription(
829 rtl::OUString(
830 RTL_CONSTASCII_USTRINGPARAM(
831 "com.sun.star.uno.XInterface::queryInterface"))),
832 false, inArgs, &ret, &outArgs);
833 throwException(exc, ret);
834 return css::uno::Reference< css::uno::XInterface >(
835 static_cast< css::uno::XInterface * >(
836 binaryToCppMapping_.mapInterface(
837 *static_cast< uno_Interface ** >(ret.getValue(ifc)),
838 ifc.get())),
839 css::uno::UNO_REF_NO_ACQUIRE);
840 }
841
getName()842 rtl::OUString Bridge::getName() throw (css::uno::RuntimeException) {
843 return name_;
844 }
845
getDescription()846 rtl::OUString Bridge::getDescription() throw (css::uno::RuntimeException) {
847 rtl::OUStringBuffer b(name_);
848 b.append(sal_Unicode(':'));
849 b.append(connection_->getDescription());
850 return b.makeStringAndClear();
851 }
852
dispose()853 void Bridge::dispose() throw (css::uno::RuntimeException) {
854 terminate();
855 // OOo expects dispose to not return while there are still remote calls in
856 // progress; an external protocol must ensure that dispose is not called
857 // from within an incoming or outgoing remote call, as passive_.wait() would
858 // otherwise deadlock:
859 passive_.wait();
860 }
861
addEventListener(css::uno::Reference<css::lang::XEventListener> const & xListener)862 void Bridge::addEventListener(
863 css::uno::Reference< css::lang::XEventListener > const & xListener)
864 throw (css::uno::RuntimeException)
865 {
866 OSL_ASSERT(xListener.is());
867 {
868 osl::MutexGuard g(mutex_);
869 if (!terminated_) {
870 listeners_.push_back(xListener);
871 return;
872 }
873 }
874 xListener->disposing(
875 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
876 }
877
removeEventListener(css::uno::Reference<css::lang::XEventListener> const & aListener)878 void Bridge::removeEventListener(
879 css::uno::Reference< css::lang::XEventListener > const & aListener)
880 throw (css::uno::RuntimeException)
881 {
882 osl::MutexGuard g(mutex_);
883 Listeners::iterator i(
884 std::find(listeners_.begin(), listeners_.end(), aListener));
885 if (i != listeners_.end()) {
886 listeners_.erase(i);
887 }
888 }
889
sendCommitChangeRequest()890 void Bridge::sendCommitChangeRequest() {
891 OSL_ASSERT(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
892 css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
893 s[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CurrentContext"));
894 std::vector< BinaryAny > a;
895 a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
896 sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
897 }
898
sendProtPropRequest(OutgoingRequest::Kind kind,std::vector<BinaryAny> const & inArguments)899 void Bridge::sendProtPropRequest(
900 OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments)
901 {
902 OSL_ASSERT(
903 kind == OutgoingRequest::KIND_REQUEST_CHANGE ||
904 kind == OutgoingRequest::KIND_COMMIT_CHANGE);
905 incrementCalls(false);
906 css::uno::TypeDescription member(
907 kind == OutgoingRequest::KIND_REQUEST_CHANGE
908 ? protPropRequest_ : protPropCommit_);
909 PopOutgoingRequest pop(
910 outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
911 getWriter()->sendDirectRequest(
912 protPropTid_, protPropOid_, protPropType_, member, inArguments);
913 pop.clear();
914 }
915
makeReleaseCall(rtl::OUString const & oid,css::uno::TypeDescription const & type)916 void Bridge::makeReleaseCall(
917 rtl::OUString const & oid, css::uno::TypeDescription const & type)
918 {
919 AttachThread att(threadPool_);
920 sendRequest(
921 att.getTid(), oid, type,
922 css::uno::TypeDescription(
923 rtl::OUString(
924 RTL_CONSTASCII_USTRINGPARAM(
925 "com.sun.star.uno.XInterface::release"))),
926 std::vector< BinaryAny >());
927 }
928
sendRequest(rtl::ByteSequence const & tid,rtl::OUString const & oid,css::uno::TypeDescription const & type,css::uno::TypeDescription const & member,std::vector<BinaryAny> const & inArguments)929 void Bridge::sendRequest(
930 rtl::ByteSequence const & tid, rtl::OUString const & oid,
931 css::uno::TypeDescription const & type,
932 css::uno::TypeDescription const & member,
933 std::vector< BinaryAny > const & inArguments)
934 {
935 getWriter()->queueRequest(tid, oid, type, member, inArguments);
936 }
937
throwException(bool exception,BinaryAny const & value)938 void Bridge::throwException(bool exception, BinaryAny const & value) {
939 if (exception) {
940 cppu::throwException(mapBinaryToCppAny(value));
941 }
942 }
943
mapBinaryToCppAny(BinaryAny const & binaryAny)944 css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
945 BinaryAny in(binaryAny);
946 css::uno::Any out;
947 out.~Any();
948 uno_copyAndConvertData(
949 &out, in.get(),
950 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
951 binaryToCppMapping_.get());
952 return out;
953 }
954
becameUnused() const955 bool Bridge::becameUnused() const {
956 return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
957 }
958
terminateWhenUnused(bool unused)959 void Bridge::terminateWhenUnused(bool unused) {
960 if (unused) {
961 // That the current thread considers the bridge unused implies that it
962 // is not within an incoming or outgoing remote call (so calling
963 // terminate cannot lead to deadlock):
964 terminate();
965 }
966 }
967
968 }
969