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