30#include <com/sun/star/bridge/InvalidProtocolChangeException.hpp>
31#include <com/sun/star/bridge/XBridge.hpp>
32#include <com/sun/star/bridge/XInstanceProvider.hpp>
33#include <com/sun/star/bridge/XProtocolProperties.hpp>
34#include <com/sun/star/connection/XConnection.hpp>
35#include <com/sun/star/io/IOException.hpp>
36#include <com/sun/star/lang/DisposedException.hpp>
37#include <com/sun/star/lang/EventObject.hpp>
38#include <com/sun/star/lang/XEventListener.hpp>
39#include <com/sun/star/uno/Reference.hxx>
40#include <com/sun/star/uno/RuntimeException.hpp>
41#include <com/sun/star/uno/Sequence.hxx>
42#include <com/sun/star/uno/XInterface.hpp>
45#include <osl/mutex.hxx>
46#include <osl/thread.hxx>
47#include <rtl/byteseq.hxx>
48#include <rtl/random.h>
50#include <rtl/string.h>
51#include <rtl/ustring.hxx>
54#include <typelib/typeclass.h>
55#include <typelib/typedescription.h>
56#include <typelib/typedescription.hxx>
57#include <uno/dispatcher.hxx>
58#include <uno/environment.hxx>
59#include <uno/lbnames.h>
78 rtl_random_getBytes(pool, &n,
sizeof n);
79 rtl_random_destroyPool(pool);
83OUString
toString(css::uno::TypeDescription
const & type) {
85 assert(d !=
nullptr &&
d->pTypeName !=
nullptr);
86 return OUString(
d->pTypeName);
89extern "C" void freeProxyCallback(
90 SAL_UNUSED_PARAMETER uno_ExtEnvironment *,
void * pProxy)
92 assert(pProxy !=
nullptr);
93 static_cast< Proxy *
>(pProxy)->do_free();
97 assert(thread !=
nullptr);
98 return osl::Thread::getCurrentIdentifier() == thread->getIdentifier();
103 explicit AttachThread(uno_ThreadPool threadPool);
107 const rtl::ByteSequence& getTid() const noexcept {
return tid_;}
110 AttachThread(
const AttachThread&) =
delete;
111 AttachThread& operator=(
const AttachThread&) =
delete;
117AttachThread::AttachThread(uno_ThreadPool threadPool):
threadPool_(threadPool) {
120 tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
124AttachThread::~AttachThread() {
130class PopOutgoingRequest {
133 OutgoingRequests & requests, rtl::ByteSequence tid,
134 OutgoingRequest
const & request);
136 ~PopOutgoingRequest();
141 PopOutgoingRequest(
const PopOutgoingRequest&) =
delete;
142 PopOutgoingRequest& operator=(
const PopOutgoingRequest&) =
delete;
145 rtl::ByteSequence
tid_;
149PopOutgoingRequest::PopOutgoingRequest(
150 OutgoingRequests & requests, rtl::ByteSequence tid,
151 OutgoingRequest
const & request):
157PopOutgoingRequest::~PopOutgoingRequest() {
163void PopOutgoingRequest::clear() {
170 com::sun::star::uno::UnoInterfaceReference
object;
177 css::uno::Reference< css::connection::XConnection >
const & connection,
178 css::uno::Reference< css::bridge::XInstanceProvider > provider):
179 factory_(factory),
name_(
std::move(
name)), connection_(connection),
181 binaryUno_(UNO_LB_UNO),
182 cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO),
183 binaryToCppMapping_(UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME),
185 reinterpret_cast<
sal_Int8 const * >(
".UrpProtocolPropertiesTid"),
186 RTL_CONSTASCII_LENGTH(
".UrpProtocolPropertiesTid")),
187 protPropOid_(
"UrpProtocolProperties"),
191 protPropRequest_(
"com.sun.star.bridge.XProtocolProperties::requestChange"),
192 protPropCommit_(
"com.sun.star.bridge.XProtocolProperties::commitChange"),
193 state_(STATE_INITIAL),
threadPool_(nullptr), currentContextMode_(false),
194 proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
195 mode_(MODE_REQUESTED)
197 assert(factory.is() && connection.is());
199 throw css::uno::RuntimeException(
"URP: no binary UNO environment");
202 throw css::uno::RuntimeException(
"URP: no C++ UNO mapping");
212 std::lock_guard g(
mutex_);
242 std::unique_lock g(
mutex_);
254 std::lock_guard g2(
mutex_);
258 if (!isThread(
reader_.get())) {
264 if (!isThread(
writer_.get())) {
271 assert(!(r.is() &&
w.is()));
284 assert(!(
final && isThread(
reader_.get())));
285 if (!isThread(
reader_.get())) {
289 joinW = !isThread(
writer_.get());
290 assert(!
final || joinW);
299 }
catch (
const css::io::IOException & e) {
300 SAL_INFO(
"binaryurp",
"caught IO exception '" << e <<
'\'');
310 assert(tp !=
nullptr);
314 std::lock_guard g(
mutex_);
317 for (
auto & stub : s)
319 for (
auto & item : stub.second)
323 "stub '" << stub.first <<
"', '" <<
toString(item.first)
324 <<
"' still mapped at Bridge::terminate");
326 binaryUno_.get()->pExtEnv, item.second.object.get());
330 for (
auto const& listener : ls)
334 css::lang::EventObject(
336 }
catch (
const css::uno::RuntimeException & e) {
337 SAL_WARN(
"binaryurp",
"caught " << e);
345 std::lock_guard g(
mutex_);
355 css::uno::Any
in(cppAny);
366 std::lock_guard g(
mutex_);
373 std::lock_guard g(
mutex_);
380 OUString
const & oid, css::uno::TypeDescription
const & type)
384 return css::uno::UnoInterfaceReference();
386 css::uno::UnoInterfaceReference obj(
findStub(oid,
type));
388 binaryUno_.get()->pExtEnv->getRegisteredInterface(
390 reinterpret_cast< void **
>(&obj.m_pUnoI), oid.pData,
391 reinterpret_cast< typelib_InterfaceTypeDescription *
>(
type.get()));
395 obj.set(
new Proxy(
this, oid,
type), SAL_NO_ACQUIRE);
397 std::lock_guard g(
mutex_);
398 assert(
proxies_ < std::numeric_limits< std::size_t >::max());
401 binaryUno_.get()->pExtEnv->registerProxyInterface(
403 reinterpret_cast< void **
>(&obj.m_pUnoI), &freeProxyCallback,
405 reinterpret_cast< typelib_InterfaceTypeDescription *
>(
413 css::uno::UnoInterfaceReference
const &
object,
414 css::uno::TypeDescription
const & type)
422 binaryUno_.get()->pExtEnv->getObjectIdentifier(
423 binaryUno_.get()->pExtEnv, &oid.pData,
object.get());
424 std::lock_guard g(
mutex_);
425 Stubs::iterator
i(
stubs_.find(oid));
427 Stub * stub =
i ==
stubs_.end() ? &newStub : &
i->second;
428 Stub::iterator j(stub->find(
type));
431 if (j == stub->end()) {
433 if (stub == &newStub) {
435 std::swap(
i->second, newStub);
436 j =
i->second.find(
type);
437 assert(j !=
i->second.end());
439 j->second.object = object;
440 j->second.references = 1;
443 reinterpret_cast< void **
>(&j->second.object.m_pUnoI),
445 reinterpret_cast< typelib_InterfaceTypeDescription *
>(
448 assert(stub != &newStub);
450 throw css::uno::RuntimeException(
451 "URP: stub reference count overflow");
453 ++j->second.references;
460 OUString
const & oid, css::uno::TypeDescription
const & type)
462 assert(!oid.isEmpty() &&
type.is());
463 std::lock_guard g(
mutex_);
464 Stubs::iterator
i(
stubs_.find(oid));
466 Stub::iterator j(
i->second.find(
type));
467 if (j !=
i->second.end()) {
468 return j->second.object;
470 for (
auto const& item :
i->second)
473 type.get(), item.first.get()))
475 return item.second.object;
479 return css::uno::UnoInterfaceReference();
483 OUString
const & oid, css::uno::TypeDescription
const & type)
485 assert(!oid.isEmpty() &&
type.is());
486 css::uno::UnoInterfaceReference obj;
489 std::lock_guard g(
mutex_);
490 Stubs::iterator
i(
stubs_.find(oid));
492 throw css::uno::RuntimeException(
"URP: release unknown stub");
494 Stub::iterator j(
i->second.find(
type));
495 if (j ==
i->second.end()) {
496 throw css::uno::RuntimeException(
"URP: release unknown stub");
498 assert(j->second.references > 0);
499 --j->second.references;
500 if (j->second.references == 0) {
501 obj = j->second.object;
503 if (
i->second.empty()) {
517 uno_Interface *
p = &proxy;
518 binaryUno_.get()->pExtEnv->registerProxyInterface(
520 reinterpret_cast< void **
>(&
p), &freeProxyCallback,
522 reinterpret_cast< typelib_InterfaceTypeDescription *
>(
535 }
catch (
const css::uno::RuntimeException & e) {
537 "binaryurp",
"caught runtime exception '" << e <<
'\'');
538 }
catch (
const std::exception & e) {
539 SAL_WARN(
"binaryurp",
"caught C++ exception '" << e.what() <<
'\'');
543 std::lock_guard g(
mutex_);
552 std::lock_guard g(
mutex_);
553 assert(
calls_ < std::numeric_limits< std::size_t >::max());
561 std::lock_guard g(
mutex_);
570 std::lock_guard g(
mutex_);
573 activeCalls_ < std::numeric_limits< std::size_t >::max());
579 std::lock_guard g(
mutex_);
580 assert(activeCalls_ <= calls_ && activeCalls_ > 0);
588 OUString
const & oid, css::uno::TypeDescription
const & member,
589 bool setter, std::vector< BinaryAny >&& inArguments,
590 BinaryAny * returnValue, std::vector< BinaryAny > * outArguments)
592 std::unique_ptr< IncomingReply > resp;
595 AttachThread att(tp);
596 PopOutgoingRequest pop(
600 att.getTid(), oid, css::uno::TypeDescription(), member,
601 std::move(inArguments));
613 throw css::lang::DisposedException(
614 "Binary URP bridge disposed during call",
617 *returnValue = resp->returnValue;
618 if (!resp->exception) {
619 *outArguments = resp->outArguments;
621 return resp->exception;
627 std::vector< BinaryAny >
a;
635 bool exception,
BinaryAny const & returnValue)
639 }
catch (css::uno::RuntimeException & e) {
648 "requestChange caught " << e <<
" in state 'requested'");
654 sal_Int32
n = *
static_cast< sal_Int32 *
>(
676 throw css::uno::RuntimeException(
677 "URP: requestChange reply with unexpected return value received",
697 bool exception,
BinaryAny const & returnValue)
702 }
catch (
const css::bridge::InvalidProtocolChangeException &) {
715 rtl::ByteSequence
const & tid, std::vector< BinaryAny >
const & inArguments)
717 assert(inArguments.size() == 1);
721 sal_Int32
n2 = *
static_cast< sal_Int32 *
>(
722 inArguments[0].getValue(
723 css::uno::TypeDescription(
739 css::uno::TypeDescription(
742 std::vector< BinaryAny >());
752 css::uno::TypeDescription(
755 std::vector< BinaryAny >(),
false);
759 throw css::uno::RuntimeException(
760 "URP: unexpected requestChange request received",
766 rtl::ByteSequence
const & tid, std::vector< BinaryAny >
const & inArguments)
768 bool bCcMode =
false;
771 assert(inArguments.size() == 1);
772 css::uno::Sequence< css::bridge::ProtocolProperty > s;
775 for (
const auto & pp : std::as_const(s)) {
776 if (pp.Name ==
"CurrentContext") {
783 css::bridge::InvalidProtocolChangeException(
784 "InvalidProtocolChangeException",
785 css::uno::Reference< css::uno::XInterface >(), pp,
810 throw css::uno::RuntimeException(
811 "URP: unexpected commitChange request received",
823 std::u16string_view oid, css::uno::TypeDescription
const & type)
const
829 std::lock_guard g(
mutex_);
834 std::lock_guard g(
mutex_);
839#if OSL_DEBUG_LEVEL > 0
841 std::lock_guard g(
mutex_);
844 "undisposed bridge \"" <<
name_ <<
"\" in state " <<
state_
845 <<
", potential deadlock ahead");
852 OUString
const & sInstanceName)
854 if (sInstanceName.isEmpty()) {
855 throw css::uno::RuntimeException(
856 "XBridge::getInstance sInstanceName must be non-empty",
859 for (sal_Int32
i = 0;
i != sInstanceName.getLength(); ++
i) {
860 if (sInstanceName[
i] > 0x7F) {
861 throw css::uno::RuntimeException(
862 "XBridge::getInstance sInstanceName contains non-ASCII"
868 std::vector< BinaryAny > inArgs;
873 std::vector< BinaryAny> outArgs;
876 css::uno::TypeDescription(
877 "com.sun.star.uno.XInterface::queryInterface"),
878 false, std::move(inArgs), &ret, &outArgs);
881 if (
t.get()->eTypeClass == typelib_TypeClass_VOID) {
884 if (!
t.equals(ifc)) {
885 throw css::uno::RuntimeException(
886 "initial object queryInterface for OID \"" + sInstanceName +
"\" returned ANY of type "
887 + OUString::unacquired(&
t.get()->pTypeName));
889 auto const val = *
static_cast< uno_Interface **
>(ret.
getValue(ifc));
890 if (val ==
nullptr) {
891 throw css::uno::RuntimeException(
892 "initial object queryInterface for OID \"" + sInstanceName
893 +
"\" returned null css.uno.XInterface ANY");
895 return css::uno::Reference< css::uno::XInterface >(
896 static_cast< css::uno::XInterface *
>(
926 css::uno::Reference< css::lang::XEventListener >
const & xListener)
928 assert(xListener.is());
930 std::lock_guard g(
mutex_);
937 xListener->disposing(
938 css::lang::EventObject(getXWeak()));
942 css::uno::Reference< css::lang::XEventListener >
const & aListener)
944 std::lock_guard g(
mutex_);
945 Listeners::iterator
i(
954 css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
955 s.getArray()[0].Name =
"CurrentContext";
967 css::uno::TypeDescription member(
970 PopOutgoingRequest pop(
978 OUString
const & oid, css::uno::TypeDescription
const & type)
994 static auto const tid = [] {
995 static sal_Int8 const id[] = {
'r',
'e',
'l',
'e',
'a',
's',
'e',
'h',
'a',
'c',
'k'};
996 return rtl::ByteSequence(
id,
std::size(
id));
1000 css::uno::TypeDescription(
"com.sun.star.uno.XInterface::release"),
1001 std::vector< BinaryAny >());
1005 rtl::ByteSequence
const & tid, OUString
const & oid,
1006 css::uno::TypeDescription
const & type,
1007 css::uno::TypeDescription
const & member,
1008 std::vector< BinaryAny >&& inArguments)
1010 getWriter()->queueRequest(tid, oid,
type, member, std::move(inArguments));
1046 throw css::lang::DisposedException(
1047 "Binary URP bridge already disposed",
uno_ThreadPool threadPool_
OutgoingRequests & requests_
com::sun::star::uno::TypeDescription getType() const noexcept
void * getValue(com::sun::star::uno::TypeDescription const &type) const noexcept
com::sun::star::uno::Mapping binaryToCppMapping_
virtual ~Bridge() override
void sendRequest(rtl::ByteSequence const &tid, OUString const &oid, com::sun::star::uno::TypeDescription const &type, com::sun::star::uno::TypeDescription const &member, std::vector< BinaryAny > &&inArguments)
void incrementActiveCalls() noexcept
void sendCommitChangeRequest()
virtual void SAL_CALL removeEventListener(com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > const &aListener) override
osl::Condition terminated_
void handleRequestChangeRequest(rtl::ByteSequence const &tid, std::vector< BinaryAny > const &inArguments)
rtl::Reference< Writer > writer_
std::vector< com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > > Listeners
void throwException(bool exception, BinaryAny const &value)
uno_ThreadPool getThreadPool()
rtl::ByteSequence protPropTid_
com::sun::star::uno::Any mapBinaryToCppAny(BinaryAny const &binaryAny)
void decrementActiveCalls() noexcept
void sendProtPropRequest(OutgoingRequest::Kind kind, std::vector< BinaryAny > const &inArguments)
void sendRequestChangeRequest()
com::sun::star::uno::Mapping cppToBinaryMapping_
com::sun::star::uno::TypeDescription protPropType_
virtual OUString SAL_CALL getDescription() override
void terminate(bool final)
uno_ThreadPool threadPool_
com::sun::star::uno::UnoInterfaceReference registerIncomingInterface(OUString const &oid, com::sun::star::uno::TypeDescription const &type)
void resurrectProxy(Proxy &proxy)
virtual com::sun::star::uno::Reference< com::sun::star::uno::XInterface > SAL_CALL getInstance(OUString const &sInstanceName) override
com::sun::star::uno::UnoInterfaceReference findStub(OUString const &oid, com::sun::star::uno::TypeDescription const &type)
std::map< com::sun::star::uno::TypeDescription, SubStub > Stub
std::map< OUString, Stub > Stubs
void terminateWhenUnused(bool unused)
rtl::Reference< Reader > reader_
void freeProxy(Proxy &proxy)
void handleRequestChangeReply(bool exception, BinaryAny const &returnValue)
virtual void SAL_CALL dispose() override
com::sun::star::uno::TypeDescription protPropCommit_
void setCurrentContextMode()
BinaryAny mapCppToBinaryAny(com::sun::star::uno::Any const &cppAny)
virtual void SAL_CALL addEventListener(com::sun::star::uno::Reference< com::sun::star::lang::XEventListener > const &xListener) override
bool makeCall(OUString const &oid, com::sun::star::uno::TypeDescription const &member, bool setter, std::vector< BinaryAny > &&inArguments, BinaryAny *returnValue, std::vector< BinaryAny > *outArguments)
OutgoingRequest lastOutgoingRequest(rtl::ByteSequence const &tid)
com::sun::star::uno::TypeDescription protPropRequest_
void incrementCalls(bool normalCall) noexcept
com::sun::star::uno::Reference< com::sun::star::connection::XConnection > connection_
void handleCommitChangeRequest(rtl::ByteSequence const &tid, std::vector< BinaryAny > const &inArguments)
void handleCommitChangeReply(bool exception, BinaryAny const &returnValue)
void releaseStub(OUString const &oid, com::sun::star::uno::TypeDescription const &type)
com::sun::star::uno::Environment binaryUno_
bool becameUnused() const
rtl::Reference< BridgeFactory > factory_
bool isCurrentContextMode()
bool isProtocolPropertiesRequest(std::u16string_view oid, com::sun::star::uno::TypeDescription const &type) const
OUString registerOutgoingInterface(com::sun::star::uno::UnoInterfaceReference const &object, com::sun::star::uno::TypeDescription const &type)
OutgoingRequests outgoingRequests_
virtual OUString SAL_CALL getName() override
void makeReleaseCall(OUString const &oid, com::sun::star::uno::TypeDescription const &type)
void revokeProxy(Proxy &proxy)
rtl::Reference< Writer > getWriter()
void pop(rtl::ByteSequence const &tid) noexcept
OutgoingRequest top(rtl::ByteSequence const &tid)
const com::sun::star::uno::TypeDescription & getType() const
static bool isProxy(rtl::Reference< Bridge > const &bridge, com::sun::star::uno::UnoInterfaceReference const &object, OUString *oid)
const OUString & getOid() const
css::uno::Reference< css::lang::XMultiServiceFactory > provider_
void SAL_CALL uno_copyAndConvertData(void *pDest, void *pSource, typelib_TypeDescription *pTypeDescr, uno_Mapping *mapping) SAL_THROW_EXTERN_C()
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
struct _typelib_TypeDescription typelib_TypeDescription
css::uno::UnoInterfaceReference get()
void SAL_CALL throwException(Any const &exc)
OUString toString(OptionInfo const *info)
com::sun::star::uno::UnoInterfaceReference object
void SAL_CALL uno_releaseIdFromCurrentThread() SAL_THROW_EXTERN_C()
void SAL_CALL uno_getIdOfCurrentThread(sal_Sequence **ppThreadId) SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_enter(uno_ThreadPool hPool, void **ppJob) SAL_THROW_EXTERN_C()
uno_ThreadPool SAL_CALL uno_threadpool_create() SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_detach(SAL_UNUSED_PARAMETER uno_ThreadPool) SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_attach(uno_ThreadPool hPool) SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_destroy(uno_ThreadPool hPool) SAL_THROW_EXTERN_C()
void SAL_CALL uno_threadpool_dispose(uno_ThreadPool hPool) SAL_THROW_EXTERN_C()
sal_Bool SAL_CALL typelib_typedescription_isAssignableFrom(typelib_TypeDescription *pAssignable, typelib_TypeDescription *pFrom) SAL_THROW_EXTERN_C()