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 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 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 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 281 css::uno::Reference< css::connection::XConnection > Bridge::getConnection() 282 const 283 { 284 return connection_; 285 } 286 287 css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider() 288 const 289 { 290 return provider_; 291 } 292 293 css::uno::Mapping & Bridge::getCppToBinaryMapping() { 294 return cppToBinaryMapping_; 295 } 296 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 308 uno_ThreadPool Bridge::getThreadPool() const { 309 OSL_ASSERT(threadPool_ != 0); 310 return threadPool_; 311 } 312 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 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.getLength() == 0) { 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 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 410 css::uno::UnoInterfaceReference Bridge::findStub( 411 rtl::OUString const & oid, css::uno::TypeDescription const & type) 412 { 413 OSL_ASSERT(oid.getLength() != 0 && 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 432 void Bridge::releaseStub( 433 rtl::OUString const & oid, css::uno::TypeDescription const & type) 434 { 435 OSL_ASSERT(oid.getLength() != 0 && 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 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 483 void Bridge::revokeProxy(Proxy & proxy) { 484 binaryUno_.get()->pExtEnv->revokeInterface( 485 binaryUno_.get()->pExtEnv, &proxy); 486 } 487 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 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 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 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 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 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 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 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 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 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 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 768 OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) { 769 OutgoingRequest req(outgoingRequests_.top(tid)); 770 outgoingRequests_.pop(tid); 771 return req; 772 } 773 774 bool Bridge::isProtocolPropertiesRequest( 775 rtl::OUString const & oid, css::uno::TypeDescription const & type) const 776 { 777 return oid == protPropOid_ && type.equals(protPropType_); 778 } 779 780 void Bridge::setCurrentContextMode() { 781 osl::MutexGuard g(mutex_); 782 currentContextMode_ = true; 783 } 784 785 bool Bridge::isCurrentContextMode() { 786 osl::MutexGuard g(mutex_); 787 return currentContextMode_; 788 } 789 790 Bridge::~Bridge() { 791 if (threadPool_ != 0) { 792 uno_threadpool_destroy(threadPool_); 793 } 794 } 795 796 css::uno::Reference< css::uno::XInterface > Bridge::getInstance( 797 rtl::OUString const & sInstanceName) throw (css::uno::RuntimeException) 798 { 799 if (sInstanceName.getLength() == 0) { 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 842 rtl::OUString Bridge::getName() throw (css::uno::RuntimeException) { 843 return name_; 844 } 845 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 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 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 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 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 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 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 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 938 void Bridge::throwException(bool exception, BinaryAny const & value) { 939 if (exception) { 940 cppu::throwException(mapBinaryToCppAny(value)); 941 } 942 } 943 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 955 bool Bridge::becameUnused() const { 956 return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_; 957 } 958 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