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