diff options
Diffstat (limited to 'bridges/source/remote')
40 files changed, 9221 insertions, 0 deletions
diff --git a/bridges/source/remote/context/context.cxx b/bridges/source/remote/context/context.cxx new file mode 100644 index 000000000000..770725f9d23f --- /dev/null +++ b/bridges/source/remote/context/context.cxx @@ -0,0 +1,499 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <stdio.h> +#include <string.h> +#include <list> +#include <hash_map> +#include <utility> + +#include <osl/diagnose.h> +#include <osl/interlck.h> +#include <osl/mutex.hxx> + +#include "rtl/ustring.hxx" + +#include <bridges/remote/context.h> +#include <bridges/remote/remote.h> +#include <bridges/remote/connection.h> +#include <bridges/remote/counter.hxx> + +using namespace ::std; +using namespace ::osl; +using namespace ::rtl; + +namespace { + +extern "C" typedef void * (SAL_CALL * MemAlloc)(sal_Size); + +} + +namespace remote_context +{ + +class remote_ContextImpl : + public remote_Context +{ +public: + remote_ContextImpl( remote_Connection *pConnection, + rtl_uString *pIdStr, + rtl_uString *pDescription, + rtl_uString *pProtocol, + remote_InstanceProvider *pProvider ); + ~remote_ContextImpl(); + + static void SAL_CALL thisAcquire( uno_Context * ); + static void SAL_CALL thisRelease( uno_Context * ); + static void * SAL_CALL thisQuery( uno_Context * , rtl_uString * ); + static void SAL_CALL thisAddDisposingListener( remote_Context * , remote_DisposingListener * ); + static void SAL_CALL thisRemoveDisposingListener( remote_Context *, remote_DisposingListener *); + static void SAL_CALL thisDispose( remote_Context *); +public: + oslInterlockedCount m_nRef; + sal_Bool m_bDisposed; + list < remote_DisposingListener * > m_lstListener; + Mutex m_mutex; +}; + + + + +struct equalOUString_Impl +{ + sal_Bool operator()(const OUString & s1, const OUString & s2) const + { return s1 == s2; } +}; + +struct hashOUString_Impl +{ + size_t operator()(const OUString & rName) const + { return rName.hashCode(); } +}; + +typedef hash_map +< + OUString, + void *, + hashOUString_Impl, + equalOUString_Impl +> +ContextMap; + +#if OSL_DEBUG_LEVEL > 1 +static MyCounter thisCounter( "DEBUG : Context" ); +#endif + +class ContextAdmin; + +ContextAdmin *g_pTheContext = 0; + + + +class ContextAdmin +{ +public: + static ContextAdmin *getInstance(); + + // listener administration + void addContextListener( remote_contextListenerFunc listener , void *pObject ); + void removeContextListener( remote_contextListenerFunc listener , void *pObject ); + + void fire( sal_Int32 nRemoteContextMode, + rtl_uString *sName, + rtl_uString *sDescription ); + + // context administration + uno_Context *createAndRegisterContext( + remote_Connection *pConnection, + rtl_uString *pIdStr, + rtl_uString *pDescription, + rtl_uString *pProtocol, + remote_InstanceProvider *pInstanceProvider ); + + void revokeContext( uno_Context *pRemoteContext ); + + uno_Context *get( rtl_uString *pHost ); + + rtl_uString ** getConnectionList( + sal_Int32 *pnStringCount, MemAlloc memAlloc ); + +private: + ::osl::Mutex m_mutex; + + ContextMap m_mapContext; + + typedef std::list< std::pair< remote_contextListenerFunc, void * > > List; + List m_lstListener; +}; + +ContextAdmin *ContextAdmin::getInstance() +{ + if( ! g_pTheContext ) { + ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() ); + if( ! g_pTheContext ) { + //TODO This memory is leaked; see #i63473# for when this should be + // changed again: + g_pTheContext = new ContextAdmin; + } + } + return g_pTheContext; +} + +void ContextAdmin::addContextListener( remote_contextListenerFunc listener , void *pObject ) +{ + ::osl::MutexGuard guard( m_mutex ); + + m_lstListener.push_back( std::make_pair( listener, pObject ) ); +} + +void ContextAdmin::removeContextListener( remote_contextListenerFunc listener , void *pObject ) +{ + ::osl::MutexGuard guard( m_mutex ); + + for (List::iterator ii(m_lstListener.begin()); ii != m_lstListener.end(); + ++ii) + { + if (ii->first == listener && ii->second == pObject) { + m_lstListener.erase( ii ); + break; + } + } +} + +void ContextAdmin::fire( + sal_Int32 nRemoteContextMode, + rtl_uString *pName, + rtl_uString *sDescription ) +{ + List lst; + { + ::osl::MutexGuard guard( m_mutex ); + lst = m_lstListener; + } + for (List::iterator i(lst.begin()); i != lst.end(); ++i) { + (i->first)(i->second, nRemoteContextMode, pName, sDescription); + } +} + +uno_Context *ContextAdmin::createAndRegisterContext( remote_Connection *pConnection, + rtl_uString *pIdStr, + rtl_uString *pDescription, + rtl_uString *pProtocol, + remote_InstanceProvider *pInstanceProvider ) +{ + ::osl::MutexGuard guard( m_mutex ); + + uno_Context *pContext = get( pIdStr ); + if( pContext ) + { + pContext->release( pContext ); + return 0; + } + + remote_ContextImpl *p = new remote_ContextImpl( pConnection, + pIdStr, + pDescription, + pProtocol, + pInstanceProvider ); + + p->aBase.acquire( (uno_Context*) p ); + + m_mapContext[ OUString( pIdStr) ] = (void*) p; + + fire( REMOTE_CONTEXT_CREATE , pIdStr , pDescription ); + return ( uno_Context * )p; +} + + +void ContextAdmin::revokeContext( uno_Context *pRemoteContext ) +{ + ::osl::MutexGuard guard( m_mutex ); + + remote_ContextImpl *p = ( remote_ContextImpl * ) pRemoteContext; + + ContextMap::iterator ii = m_mapContext.find( p->m_pName ); + OSL_ASSERT( ii != m_mapContext.end() ); + m_mapContext.erase( ii ); + + fire( REMOTE_CONTEXT_DESTROY , p->m_pName , p->m_pDescription ); + +} + +uno_Context *ContextAdmin::get( rtl_uString *pHost ) +{ + ::osl::MutexGuard guard( m_mutex ); + + ContextMap::iterator ii = m_mapContext.find( OUString( (rtl_uString*)pHost ) ); + if( ii == m_mapContext.end() ) + { + return 0; + } + + uno_Context *p = ( uno_Context * ) (*ii).second; + p->acquire( p ); + return p; +} + + +rtl_uString ** ContextAdmin::getConnectionList( + sal_Int32 *pnStringCount, MemAlloc memAlloc ) +{ + ::osl::MutexGuard guard( m_mutex ); + + *pnStringCount = m_mapContext.size(); + rtl_uString **ppReturn = ( rtl_uString ** ) + memAlloc( sizeof( rtl_uString * ) * m_mapContext.size() ); + memset( ppReturn , 0 , sizeof( rtl_uString * ) * m_mapContext.size() ); + + sal_Int32 i = 0; + for( ContextMap::iterator ii = m_mapContext.begin() ; + ii != m_mapContext.end(); + ++ii, i++ ) + { + rtl_uString_assign( &( ppReturn[i] ), (*ii).first.pData ); + } + + return ppReturn; +} + + + +/***************************** + * remote_ContextImpl implementation + ****************************/ + + + +remote_ContextImpl::remote_ContextImpl( remote_Connection *pConnection , + rtl_uString *pIdStr, + rtl_uString *pDescription, + rtl_uString *pProtocol, + remote_InstanceProvider *pProvider ) : + m_nRef( 0 ), + m_bDisposed( sal_False ) +{ + m_pConnection = pConnection; + m_pConnection->acquire( m_pConnection ); + + m_pInstanceProvider = pProvider; + if( m_pInstanceProvider ) + { + m_pInstanceProvider->acquire( pProvider ); + } + + m_pName = pIdStr; + rtl_uString_acquire( m_pName ); + + m_pDescription = pDescription; + rtl_uString_acquire( m_pDescription ); + + m_pProtocol = pProtocol; + rtl_uString_acquire( pProtocol ); + + aBase.acquire = thisAcquire; + aBase.release = thisRelease; + addDisposingListener = thisAddDisposingListener; + removeDisposingListener = thisRemoveDisposingListener; + dispose = thisDispose; +#if OSL_DEBUG_LEVEL > 1 + thisCounter.acquire(); +#endif +} + +remote_ContextImpl::~remote_ContextImpl() +{ + // disposed must have been called + OSL_ASSERT( m_bDisposed ); + + rtl_uString_release( m_pName ); + rtl_uString_release( m_pDescription ); + rtl_uString_release( m_pProtocol ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.release(); +#endif + +} + + +void remote_ContextImpl::thisAddDisposingListener( remote_Context *pRemoteC , + remote_DisposingListener *pListener ) +{ + remote_ContextImpl *pImpl = (remote_ContextImpl * ) pRemoteC; + + ::osl::MutexGuard guard( pImpl->m_mutex ); + + pListener->acquire( pListener ); + pImpl->m_lstListener.push_back( pListener ); +} + +void remote_ContextImpl::thisRemoveDisposingListener( remote_Context *pRemoteC, + remote_DisposingListener *pListener) +{ + remote_ContextImpl *pImpl = (remote_ContextImpl * ) pRemoteC; + MutexGuard guard( pImpl->m_mutex ); + + for( list< remote_DisposingListener * >::iterator ii = pImpl->m_lstListener.begin() ; + ii != pImpl->m_lstListener.end(); + ++ii ) + { + if( (*ii) == pListener ) + { + pImpl->m_lstListener.erase( ii ); + pListener->release( pListener ); + break; + } + } +} + +void remote_ContextImpl::thisDispose( remote_Context *pRemoteC ) +{ + remote_ContextImpl *pImpl = ( remote_ContextImpl * )pRemoteC; + + MutexGuard guard( pImpl->m_mutex ); + if( ! pImpl->m_bDisposed ) + { + pImpl->m_bDisposed = sal_True; + ContextAdmin::getInstance()->revokeContext( (uno_Context * ) pRemoteC ); + + if( pImpl->m_pInstanceProvider ) + { + pImpl->m_pInstanceProvider->release( pImpl->m_pInstanceProvider ); + pImpl->m_pInstanceProvider = 0; + } + + pImpl->m_pConnection->release( pImpl->m_pConnection ); + pImpl->m_pConnection = 0; + + list< remote_DisposingListener * > lst = pImpl->m_lstListener; + pImpl->m_lstListener.clear(); + + for( list < remote_DisposingListener * >::iterator ii = lst.begin(); + ii != lst.end(); + ++ii ) + { + (*ii)->disposing( (*ii) , pImpl->m_pName ); + (*ii)->release( (*ii) ); + } + + } +} + + + +void remote_ContextImpl::thisAcquire( uno_Context *pRemoteC ) +{ + remote_ContextImpl *p = SAL_REINTERPRET_CAST(remote_ContextImpl * ,pRemoteC ); + osl_incrementInterlockedCount( &(p->m_nRef) ); +} + +void remote_ContextImpl::thisRelease( uno_Context *pRemoteC ) +{ + remote_ContextImpl *p = SAL_REINTERPRET_CAST( remote_ContextImpl * , pRemoteC ); + if (! osl_decrementInterlockedCount( &(p->m_nRef) )) + { + // enshure, that this piece of code is not reentered + osl_incrementInterlockedCount( &(p->m_nRef) ); + + // dispose, if necessary + p->dispose( p ); + + // restore the counter + osl_decrementInterlockedCount( &(p->m_nRef) ); + + if( 0 == p->m_nRef ) + { + delete p; + } + else + { + // reanimated, but disposed ! + } + } +} + +void *remote_ContextImpl::thisQuery( uno_Context * , rtl_uString * ) +{ + return 0; +} + + +} // end namespace remote_context + + +using namespace remote_context; + +//----------------------- +// +// C-Interface +// +//----------------------- +extern "C" remote_Context * SAL_CALL +remote_getContext( rtl_uString *pIdString ) +{ + return (remote_Context *) ContextAdmin::getInstance()->get( pIdString ); +} + + + +extern "C" remote_Context * SAL_CALL +remote_createContext( remote_Connection *pConnection, + rtl_uString *pIdStr, + rtl_uString *pDescription, + rtl_uString *pProtocol, + remote_InstanceProvider *pProvider ) +{ + remote_ContextImpl *p = (remote_ContextImpl * ) + ContextAdmin::getInstance()->createAndRegisterContext( + pConnection , + pIdStr , + pDescription, + pProtocol, + pProvider ); + + return (remote_Context * )p; +} + + +extern "C" void SAL_CALL +remote_addContextListener( remote_contextListenerFunc listener, void *pObject ) +{ + ContextAdmin::getInstance()->addContextListener( listener , pObject ); +} + +extern "C" void SAL_CALL +remote_removeContextListener( remote_contextListenerFunc listener , void *pObject ) +{ + ContextAdmin::getInstance()->removeContextListener( listener , pObject ); +} + +extern "C" rtl_uString ** SAL_CALL +remote_getContextList( sal_Int32 *pnStringCount, MemAlloc memAlloc ) +{ + return ContextAdmin::getInstance()->getConnectionList( pnStringCount , memAlloc ); +} diff --git a/bridges/source/remote/context/exports.dxp b/bridges/source/remote/context/exports.dxp new file mode 100644 index 000000000000..dcef3c369b10 --- /dev/null +++ b/bridges/source/remote/context/exports.dxp @@ -0,0 +1,5 @@ +remote_getContext +remote_createContext +remote_getContextList +remote_removeContextListener +remote_addContextListener
\ No newline at end of file diff --git a/bridges/source/remote/context/makefile.mk b/bridges/source/remote/context/makefile.mk new file mode 100644 index 000000000000..cc2a52355d25 --- /dev/null +++ b/bridges/source/remote/context/makefile.mk @@ -0,0 +1,65 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=bridges +TARGET=rmcxt +ENABLE_EXCEPTIONS=TRUE +USE_DEFFILE=TRUE + +UNIXVERSIONNAMES=UDK + +# --- Settings ----------------------------------------------------- +.INCLUDE : settings.mk +# ------------------------------------------------------------------ + +UNOUCRDEP=$(SOLARUCRDIR)$/uce.rdb +UNOUCRRDB=$(SOLARUCRDIR)$/uce.rdb + +SLOFILES= $(SLO)$/context.obj + +SHL1TARGET= $(TARGET) + +SHL1STDLIBS= \ + $(SALLIB) + +SHL1DEPN= +SHL1IMPLIB= i$(TARGET) +SHL1LIBS= $(SLB)$/$(TARGET).lib +SHL1DEF= $(MISC)$/$(SHL1TARGET).def +SHL1RPATH=URELIB + +SHL1VERSIONMAP= $(TARGET).map + +DEF1NAME= $(SHL1TARGET) +#DEF1EXPORTFILE= exports.dxp + + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/bridges/source/remote/context/rmcxt.map b/bridges/source/remote/context/rmcxt.map new file mode 100755 index 000000000000..182f6495ea9d --- /dev/null +++ b/bridges/source/remote/context/rmcxt.map @@ -0,0 +1,10 @@ +UDK_3_0_0 { + global: + remote_getContext; + remote_createContext; + remote_getContextList; + remote_removeContextListener; + remote_addContextListener; + local: + *; +}; diff --git a/bridges/source/remote/idl/corba.idl b/bridges/source/remote/idl/corba.idl new file mode 100644 index 000000000000..b71d16e2eff1 --- /dev/null +++ b/bridges/source/remote/idl/corba.idl @@ -0,0 +1,88 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +module com +{ +module sun +{ +module star +{ + +module corba +{ + + // CosBridging module + typedef unsigned long ObjectSystemID; + typedef sequence< byte > OpaqueData; + + struct OneThreadID + { + ObjectSystemID objSysID; + OpaqueData threadID; + }; + + typedef sequence<OneThreadID> ThreadIDs; + + struct LogicalThreadID // Service context + { + ThreadIDs IDs; + }; + + struct CorbaString8 + { + string theString; + }; + + struct CorbaUnion + { + long dummy; + }; + + struct ObjectKey + { + CorbaString8 sOid; + CorbaString8 sType; + }; + + enum TCKind + { + tk_null, tk_void, + tk_short, tk_long, tk_ushort, tk_ulong, + tk_float, tk_double, tk_boolean, tk_char, + tk_octet, tk_any, tk_TypeCode, tk_Principal, tk_objref, + tk_struct, tk_union, tk_enum, tk_string, + tk_sequence, tk_array, tk_alias, tk_except, + tk_longlong, tk_ulonglong, tk_longdouble, + tk_wchar, tk_wstring, tk_fixed, + tk_value, tk_value_box, + tk_native, + tk_abstract_interface + }; +}; + +}; +}; +}; diff --git a/bridges/source/remote/static/helper.cxx b/bridges/source/remote/static/helper.cxx new file mode 100644 index 000000000000..1ad421cedecc --- /dev/null +++ b/bridges/source/remote/static/helper.cxx @@ -0,0 +1,209 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <rtl/alloc.h> +#include <osl/diagnose.h> + +#include <bridges/remote/helper.hxx> + +#include <bridges/remote/stub.hxx> +#include <bridges/remote/proxy.hxx> +#include <bridges/remote/remote.hxx> + +#include <com/sun/star/uno/Sequence.hxx> + +using namespace ::rtl; +using namespace ::com::sun::star::uno; + +namespace bridges_remote +{ + +void SAL_CALL remote_createStub ( + remote_Interface **ppRemoteI, + rtl_uString *pOid , + typelib_TypeDescriptionReference *pTypeRef, + uno_Environment *pEnvRemote, + ReleaseRemoteCallbackFunc releaseRemoteCallback ) +{ + typelib_TypeDescription *pType = 0; + typelib_typedescriptionreference_getDescription( &pType, pTypeRef ); + + (void) pEnvRemote->pExtEnv->getRegisteredInterface( + pEnvRemote->pExtEnv, + (void **)ppRemoteI, + pOid, + (typelib_InterfaceTypeDescription* )pType ); + + if( *ppRemoteI ) + { + if( (*ppRemoteI)->acquire == acquireRemote2RemoteStub ) { + + if( releaseRemoteCallback ) + { + // use the callback handler, the bridge wants to send the call immeadiatly + releaseRemoteCallback( *ppRemoteI , pOid, pTypeRef , pEnvRemote ); + } + else + { + ((::bridges_remote::Remote2RemoteStub *)*ppRemoteI)->releaseRemote(); + } + } + else + { + // Uno2RemoteStub + // no release necessary + } + } + else + { + remote_BridgeImpl *pImpl = ((remote_Context *)pEnvRemote->pContext)->m_pBridgeImpl; + *ppRemoteI = + new ::bridges_remote::Remote2RemoteStub( + pOid, + (typelib_InterfaceTypeDescription * ) pType, + pEnvRemote, + pImpl->m_sendRequest); + + // ppRemoteI may change during registration + pEnvRemote->pExtEnv->registerProxyInterface( + pEnvRemote->pExtEnv, + (void **) ppRemoteI, + freeRemote2RemoteStub, + pOid, + (typelib_InterfaceTypeDescription * ) pType ); + } + + typelib_typedescription_release( pType ); +} + +void SAL_CALL remote_sendQueryInterface( + uno_Environment *pEnvRemote, + remote_Interface **ppRemoteI, + rtl_uString *pOid , + typelib_TypeDescriptionReference *pTypeRef, + uno_Any **ppException + ) +{ + OSL_ASSERT( ppRemoteI ); + + typelib_InterfaceTypeDescription *pType = 0; + typelib_typedescriptionreference_getDescription( (typelib_TypeDescription ** )&pType, pTypeRef ); + + if( *ppRemoteI ) + { + (*ppRemoteI)->release( *ppRemoteI ); + (*ppRemoteI) = 0; + } + + remote_BridgeImpl *pImpl = ((remote_Context *)pEnvRemote->pContext)->m_pBridgeImpl; + + Type type = ::getCppuType( (Reference < XInterface > *)0 ); + + // get type for queryInterface + OUString sCompleteMethodName = type.getTypeName(); + sCompleteMethodName += OUString::createFromAscii("::queryInterface"); + + typelib_InterfaceMemberTypeDescription *pMemberType = 0; + typelib_typedescription_getByName( + (typelib_TypeDescription **) &pMemberType, + sCompleteMethodName.pData ); + + OSL_ASSERT( pMemberType ); + + uno_Any anyInterface; + anyInterface.pType = 0; + anyInterface.pData = 0; + + void *pReturn = &anyInterface; + void *ppArgs[1]; + + ppArgs[0] = 0; + typelib_TypeDescriptionReference *pRef = 0; + typelib_typedescriptionreference_new( &pRef , + pType->aBase.eTypeClass, + pType->aBase.pTypeName); + + ppArgs[0] = &pRef; + +// uno_Any anyException; +// uno_Any *pAnyException = &anyException; + + // do the queryInterface + pImpl->m_sendRequest( + pEnvRemote, + (typelib_TypeDescription * ) pMemberType, + pOid, + pType, + pReturn, + ppArgs, + ppException ); + + + // now release everything + typelib_typedescriptionreference_release( pRef ); + typelib_typedescription_release( (typelib_TypeDescription * ) pMemberType ); + + if( *ppException ) + { + *ppRemoteI = 0; + } + else + { + // set out parameter + if( typelib_TypeClass_INTERFACE == anyInterface.pType->eTypeClass ) + { + *ppRemoteI = ( remote_Interface * ) anyInterface.pReserved; + } + typelib_typedescriptionreference_release( anyInterface.pType ); + } + + typelib_typedescription_release( (typelib_TypeDescription * ) pType ); +} + + +void SAL_CALL remote_retrieveOidFromProxy( + remote_Interface *pRemoteI, + rtl_uString **ppOid ) +{ + if( pRemoteI->acquire == acquireRemote2RemoteStub ) + { + // Remote2RemoteStub + ::bridges_remote::Remote2RemoteStub *pStub = (::bridges_remote::Remote2RemoteStub * ) pRemoteI; + rtl_uString_newFromString( ppOid , pStub->m_sOid.pData ); + } + else + { + // Uno2RemoteStub + ::bridges_remote::Uno2RemoteStub *pStub = (::bridges_remote::Uno2RemoteStub * ) pRemoteI; + rtl_uString_newFromString( ppOid , pStub->m_sOid.pData ); + pRemoteI->acquire( pRemoteI ); + } +} + +} diff --git a/bridges/source/remote/static/makefile.mk b/bridges/source/remote/static/makefile.mk new file mode 100644 index 000000000000..9b3c2b795f8d --- /dev/null +++ b/bridges/source/remote/static/makefile.mk @@ -0,0 +1,61 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=bridges +TARGET=bridges_remote_static +ENABLE_EXCEPTIONS=TRUE +USE_DEFFILE=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# ------------------------------------------------------------------ + +SLOFILES= \ + $(SLO)$/proxy.obj \ + $(SLO)$/stub.obj \ + $(SLO)$/remote.obj \ + $(SLO)$/mapping.obj \ + $(SLO)$/helper.obj \ + $(SLO)$/remote_types.obj + +# Forte6 update 1 on Solaris Intel dies with internal compiler error +# on stub.cxx if optimization is on. Switch it off for now. +# To be reevaluated on compiler upgrade +.IF "$(OS)$(CPU)"=="SOLARISI" +NOOPTFILES=\ + $(SLO)$/stub.obj +.ENDIF + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + + diff --git a/bridges/source/remote/static/mapping.cxx b/bridges/source/remote/static/mapping.cxx new file mode 100644 index 000000000000..69e079d14eaf --- /dev/null +++ b/bridges/source/remote/static/mapping.cxx @@ -0,0 +1,218 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <osl/diagnose.h> + +#include <bridges/remote/proxy.hxx> +#include <bridges/remote/stub.hxx> +#include <bridges/remote/counter.hxx> +#include <bridges/remote/mapping.hxx> + +using namespace bridges_remote; + +extern "C" { + +static void SAL_CALL thisAcquire( uno_Mapping *pMap ) +{ + RemoteMapping *p = SAL_REINTERPRET_CAST( RemoteMapping * , pMap ); + if( 1 == osl_incrementInterlockedCount( &(p->m_nRef) ) ) + { + if( remoteToUno == pMap->mapInterface ) + { + uno_registerMapping( &pMap , + freeRemoteMapping, + p->pEnvRemote , + p->pEnvUno , + p->m_sPurpose.pData ); + } + else + { + uno_registerMapping( &pMap , + freeRemoteMapping, + p->pEnvUno , + p->pEnvRemote , + p->m_sPurpose.pData ); + } + + } +} + +static void SAL_CALL thisRelease( uno_Mapping *pMap ) +{ + RemoteMapping *p = SAL_REINTERPRET_CAST( RemoteMapping * , pMap ); + if (! osl_decrementInterlockedCount( &(p->m_nRef) )) + { + uno_revokeMapping( pMap ); + } +} + +} + +namespace bridges_remote { + +void remoteToUno( uno_Mapping *pMapping, void **ppUnoI, void *pRemoteI, + typelib_InterfaceTypeDescription *pTypeDescr ) +{ + remote_Mapping *pRemoteMapping = ( remote_Mapping * ) pMapping; + + OSL_ASSERT( ppUnoI && pTypeDescr ); + if (*ppUnoI) + { + ((uno_Interface *)*ppUnoI)->release( (uno_Interface *)*ppUnoI ); + *ppUnoI = 0; + } + + if (pRemoteI && pTypeDescr) + { + // get object id of interface to be wrapped + rtl_uString * pOid = 0; + pRemoteMapping->pEnvRemote->pExtEnv->getObjectIdentifier( + pRemoteMapping->pEnvRemote->pExtEnv, + &pOid, + pRemoteI ); + + OSL_ASSERT(pOid); + if( ! pOid ) + { + return; + } + + // try to get any known interface from target environment + pRemoteMapping->pEnvUno->pExtEnv->getRegisteredInterface( + pRemoteMapping->pEnvUno->pExtEnv, + ppUnoI, + pOid, + pTypeDescr); + + if ( ! *ppUnoI) // already existing interface + { + // try to publish a new proxy; proxy may be exchanged during registration + *ppUnoI = new Remote2UnoProxy( + ( remote_Interface * ) pRemoteI, + pOid, + pTypeDescr , + pRemoteMapping->pEnvUno, + pRemoteMapping->pEnvRemote); + + pRemoteMapping->pEnvUno->pExtEnv->registerProxyInterface( + pRemoteMapping->pEnvUno->pExtEnv, + ppUnoI, + freeRemote2UnoProxy, + pOid, + pTypeDescr ); + + OSL_ASSERT( *ppUnoI ); + } + rtl_uString_release( pOid ); + } +} + +void unoToRemote( uno_Mapping *pMapping, void **ppRemoteI, void *pUnoI, + typelib_InterfaceTypeDescription *pTypeDescr ) +{ + remote_Mapping *pRemoteMapping = ( remote_Mapping * ) pMapping; + OSL_ASSERT( ppRemoteI && pTypeDescr ); + if (*ppRemoteI) + { + ((remote_Interface *)*ppRemoteI)->release( (remote_Interface *)*ppRemoteI); + *ppRemoteI = 0; + } + if (pUnoI && pTypeDescr) + { + // get object id of interface to be wrapped + rtl_uString * pOid = 0; + pRemoteMapping->pEnvUno->pExtEnv->getObjectIdentifier( + pRemoteMapping->pEnvUno->pExtEnv, + &pOid, + pUnoI ); + + OSL_ASSERT( pOid ); + if( ! pOid ) + { + return; + } + + pRemoteMapping->pEnvRemote->pExtEnv->getRegisteredInterface( + pRemoteMapping->pEnvRemote->pExtEnv, + (void**)ppRemoteI, + pOid, + pTypeDescr ); + + if( !*ppRemoteI ) + { + // try to publish a new proxy; + *ppRemoteI = new Uno2RemoteStub( + ( uno_Interface * ) pUnoI, + pOid, + pTypeDescr, + pRemoteMapping->pEnvUno, + pRemoteMapping->pEnvRemote ); + + // note : ppRemoteI may change during registration + pRemoteMapping->pEnvRemote->pExtEnv->registerProxyInterface( + pRemoteMapping->pEnvRemote->pExtEnv, + (void**) ppRemoteI, + freeUno2RemoteStub, + pOid, + pTypeDescr ); + } + + rtl_uString_release( pOid ); + } +} + +void freeRemoteMapping(uno_Mapping * mapping) { + delete reinterpret_cast< RemoteMapping * >(mapping); +} + +RemoteMapping::RemoteMapping( uno_Environment *pEnvUno_ , + uno_Environment *pEnvRemote_, + uno_MapInterfaceFunc func, + const ::rtl::OUString sPurpose) : + m_nRef( 1 ), + m_sPurpose( sPurpose ) +{ + pEnvUno = pEnvUno_; + pEnvRemote = pEnvRemote_; + + pEnvUno->acquire( pEnvUno ); + pEnvRemote->acquire( pEnvRemote ); + + aBase.mapInterface = func; + aBase.acquire = thisAcquire; + aBase.release = thisRelease; +} + +RemoteMapping::~RemoteMapping( ) +{ + pEnvUno->release( pEnvUno ); + pEnvRemote->release( pEnvRemote ); +} + +} diff --git a/bridges/source/remote/static/proxy.cxx b/bridges/source/remote/static/proxy.cxx new file mode 100644 index 000000000000..da67e9bd17ec --- /dev/null +++ b/bridges/source/remote/static/proxy.cxx @@ -0,0 +1,338 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <sal/alloca.h> +#include <bridges/remote/proxy.hxx> +#include <bridges/remote/context.h> + +#include <uno/data.h> +#include <uno/mapping.hxx> +#include <uno/environment.h> + +#include <com/sun/star/uno/Any.hxx> + +#include <bridges/remote/bridgeimpl.hxx> + +#include "remote_types.hxx" + +#if OSL_DEBUG_LEVEL > 1 +#include <bridges/remote/counter.hxx> +static MyCounter thisCounter( "DEBUG : Remote2UnoProxy"); +#endif + +using namespace ::bridges_remote; +using namespace ::com::sun::star::uno; + +extern "C" { + +void SAL_CALL remote_release( void *pRemoteI ) +{ + ((remote_Interface * )pRemoteI)->release( (remote_Interface * ) pRemoteI ); +} + +} + +namespace bridges_remote { + +void freeRemote2UnoProxy(uno_ExtEnvironment *, void * proxy) { + delete static_cast< Remote2UnoProxy * >(proxy); +} + +void acquireRemote2UnoProxy( uno_Interface *pThis ) +{ + Remote2UnoProxy *p = ( Remote2UnoProxy * ) pThis; + if( 1 == osl_incrementInterlockedCount( &(p->m_nRef) ) ) + { + p->m_pEnvUno->pExtEnv->registerProxyInterface( + p->m_pEnvUno->pExtEnv, + (void**)&pThis, + freeRemote2UnoProxy, + p->m_sOid.pData, + p->m_pType ); + OSL_ASSERT( (uno_Interface *)p == pThis ); + } +} + +void releaseRemote2UnoProxy( uno_Interface *pThis ) +{ + Remote2UnoProxy *p = ( Remote2UnoProxy * ) pThis; + if ( 0 == osl_decrementInterlockedCount( &(p->m_nRef) )) + { + p->m_pEnvUno->pExtEnv->revokeInterface( p->m_pEnvUno->pExtEnv, p ); + } +} + +void SAL_CALL dispatchRemote2UnoProxy( + uno_Interface * pUnoI, + typelib_TypeDescription const * pType, + void * pReturn, + void * ppArgs[], + uno_Any ** ppException ) +{ + Remote2UnoProxy *p = ( Remote2UnoProxy * ) pUnoI; + RemoteThreadCounter counter( p->m_pEnvRemote ); + + typelib_InterfaceMethodTypeDescription *pMethodType = 0; + typelib_InterfaceAttributeTypeDescription *pAttributeType = 0; + typelib_TypeDescription *pReturnType = 0; + typelib_TypeDescription **ppArgType = 0; + sal_Int32 nArgCount = 0; + sal_Bool *pbIsIn = 0; + sal_Bool *pbIsOut = 0; + sal_Bool *pbConversionNeeded = 0; + sal_Bool bConversionNeededForReturn = 0; + + //-------------------------------- + // Collect all needed types ! + //-------------------------------- + if( typelib_TypeClass_INTERFACE_ATTRIBUTE == pType->eTypeClass ) + { + pAttributeType = ( typelib_InterfaceAttributeTypeDescription * ) pType; + if( pReturn ) + { + TYPELIB_DANGER_GET( &pReturnType , pAttributeType->pAttributeTypeRef ); + bConversionNeededForReturn = remote_relatesToInterface( pReturnType ); + } + else + { + nArgCount = 1; + ppArgType = (typelib_TypeDescription **) alloca( sizeof( void * ) ); + pbIsIn = ( sal_Bool * ) alloca( sizeof( sal_Bool ) ); + pbIsOut = ( sal_Bool * ) alloca( sizeof( sal_Bool ) ); + pbConversionNeeded = ( sal_Bool *) alloca( sizeof( sal_Bool ) ); + + pbIsIn[0] = sal_True; + pbIsOut[0] = sal_False; + ppArgType[0] = 0; + TYPELIB_DANGER_GET( &( ppArgType[0] ) , pAttributeType->pAttributeTypeRef ); + pbConversionNeeded[0] = remote_relatesToInterface( ppArgType[0] ); + + } + } + if( typelib_TypeClass_INTERFACE_METHOD == pType->eTypeClass ) + { + pMethodType = ( typelib_InterfaceMethodTypeDescription * ) pType; + TYPELIB_DANGER_GET( &pReturnType , pMethodType->pReturnTypeRef ); + bConversionNeededForReturn = remote_relatesToInterface( pReturnType ); + nArgCount = pMethodType->nParams; + ppArgType = (typelib_TypeDescription **) alloca( sizeof( void * ) * nArgCount ); + pbIsIn = (sal_Bool * ) alloca( sizeof( sal_Bool ) * nArgCount ); + pbIsOut = (sal_Bool * ) alloca( sizeof( sal_Bool ) * nArgCount ); + pbConversionNeeded = ( sal_Bool *) alloca( sizeof( sal_Bool ) * nArgCount ); + sal_Int32 i; + for( i = 0 ; i < nArgCount ; i ++ ) + { + ppArgType[i] = 0; + TYPELIB_DANGER_GET( & (ppArgType[i]) , pMethodType->pParams[i].pTypeRef ); + pbIsIn[i] = pMethodType->pParams[i].bIn; + pbIsOut[i] = pMethodType->pParams[i].bOut; + pbConversionNeeded[i] = remote_relatesToInterface( ppArgType[i] ); + } + } + + void *pRemoteReturn = 0; + if( pReturnType ) + { + if( bConversionNeededForReturn ) + { + pRemoteReturn = alloca( pReturnType->nSize ); + } + else + { + pRemoteReturn = pReturn; + } + } + + void ** ppRemoteArgs = 0; + if( nArgCount ) + { + ppRemoteArgs = (void**) alloca( sizeof( void * ) * nArgCount ); + } + + sal_Int32 i; + for( i = 0 ; i < nArgCount ; i ++ ) + { + if( pbConversionNeeded[i] ) + { + ppRemoteArgs[i] = alloca( ppArgType[i]->nSize ); + + if( pbIsIn[i] ) { + uno_copyAndConvertData( + ppRemoteArgs[i], + ppArgs[i], + ppArgType[i], + p->m_mapUno2Remote.get() ); + } + } + else + { + ppRemoteArgs[i] = ppArgs[i]; + } + } + + uno_Any any; + uno_Any *pAny = &any; + + p->m_pRemoteI->pDispatcher( p->m_pRemoteI, + pType, + pRemoteReturn, + ppRemoteArgs, + &pAny ); + + if( ! pAny ) + { + if( pReturn && bConversionNeededForReturn ) + { + uno_copyAndConvertData( + pReturn , + pRemoteReturn, + pReturnType, + p->m_mapRemote2Uno.get() ); + uno_destructData( pRemoteReturn , pReturnType , remote_release ); + } + + sal_Int32 j; + for( j = 0 ; j < nArgCount ; j ++ ) + { + if( pbConversionNeeded[j] ) + { + if( pbIsIn[j] ) { + if( pbIsOut[j] ) { + uno_destructData( ppArgs[j] , + ppArgType[j] , + 0 ); + uno_copyAndConvertData( ppArgs[j] , + ppRemoteArgs[j], + ppArgType[j], + p->m_mapRemote2Uno.get() ); + } + } + else // pure out + { + uno_copyAndConvertData( ppArgs[j] , + ppRemoteArgs[j], + ppArgType[j], + p->m_mapRemote2Uno.get() ); + } + uno_destructData( ppRemoteArgs[j], + ppArgType[j], + remote_release ); + } + } + *ppException = 0; + } + else + { + // ----------------------- + // an exception occured + // ----------------------- + typelib_TypeDescription *pAnyType = 0; + getCppuType( (::com::sun::star::uno::Any*) 0 ).getDescription( &pAnyType ); + uno_copyAndConvertData( *ppException , + pAny , + pAnyType, + p->m_mapRemote2Uno.get() ); + uno_destructData( pAny , pAnyType , remote_release ); + typelib_typedescription_release( pAnyType ); + + // destruct remote in parameters ( out parameters have not been constructed ) + for( i = 0 ; i < nArgCount ; i ++ ) + { + if( pbConversionNeeded[i] && pbIsIn[i] ) + { + uno_destructData( ppRemoteArgs[i], + ppArgType[i], + remote_release ); + } + } + } + + //-------------------------- + // release all acquired types + //-------------------------- + if( pReturnType ) + { + TYPELIB_DANGER_RELEASE( pReturnType ); + } + for( i = 0 ; i < nArgCount ; i ++ ) + { + TYPELIB_DANGER_RELEASE( ppArgType[ i] ); + } + +} + +Remote2UnoProxy::Remote2UnoProxy( remote_Interface *pRemoteI, + rtl_uString *pOid, + typelib_InterfaceTypeDescription *pType, + uno_Environment *pEnvUno, + uno_Environment *pEnvRemote ) : + m_sOid( pOid ), + m_pType( pType ), + m_pRemoteI( pRemoteI ), + m_pEnvUno( pEnvUno ), + m_pEnvRemote( pEnvRemote ), + m_mapRemote2Uno( pEnvRemote, pEnvUno ), + m_mapUno2Remote( pEnvUno , pEnvRemote ), + m_nRef( 1 ) +{ + typelib_typedescription_acquire( (typelib_TypeDescription * ) m_pType ); + m_pEnvUno->acquire( m_pEnvUno ); + m_pEnvRemote->acquire( m_pEnvRemote ); + + acquire = acquireRemote2UnoProxy; + release = releaseRemote2UnoProxy; + pDispatcher = dispatchRemote2UnoProxy; + + m_pEnvRemote->pExtEnv->registerInterface( + m_pEnvRemote->pExtEnv, + (void**)&m_pRemoteI, + m_sOid.pData, + m_pType ); + m_pRemoteI->acquire( m_pRemoteI ); + +#if OSL_DEBUG_LEVEL > 1 + thisCounter.acquire(); +#endif +} + +Remote2UnoProxy::~Remote2UnoProxy() +{ + // revoke external ref (oid) + m_pEnvRemote->pExtEnv->revokeInterface( m_pEnvRemote->pExtEnv , m_pRemoteI ); + + typelib_typedescription_release( (typelib_TypeDescription * )m_pType ); + m_pRemoteI->release( m_pRemoteI ); + m_pEnvUno->release( m_pEnvUno ); + m_pEnvRemote->release( m_pEnvRemote ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.release(); +#endif +} + +} // end namespace bridge_remote diff --git a/bridges/source/remote/static/remote.cxx b/bridges/source/remote/static/remote.cxx new file mode 100644 index 000000000000..6129d91829ba --- /dev/null +++ b/bridges/source/remote/static/remote.cxx @@ -0,0 +1,161 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <bridges/remote/remote.hxx> +#include <bridges/remote/counter.hxx> + +#if OSL_DEBUG_LEVEL > 1 +static MyCounter thisCounter( "DEBUG : Remote2RemoteStub"); +#endif + +using namespace bridges_remote; + +extern "C" { + +static void SAL_CALL thisRelease( remote_Interface *pThis ) +{ + Remote2RemoteStub *p = ( Remote2RemoteStub * ) pThis; + if (! osl_decrementInterlockedCount( &(p->m_nRef) )) + { + p->m_pEnvRemote->pExtEnv->revokeInterface( p->m_pEnvRemote->pExtEnv, pThis ); + + } +} + +static void SAL_CALL thisDispatch( + remote_Interface * pRemoteI, + typelib_TypeDescription const * pMemberType, + void * pReturn, + void * pArgs[], + uno_Any ** ppException ) +{ + Remote2RemoteStub *pThis = ( Remote2RemoteStub * ) pRemoteI; + + pThis->m_dispatch( pThis->m_pEnvRemote, + pMemberType, + pThis->m_sOid.pData, + pThis->m_pType, + pReturn, + pArgs, + ppException ); +} + +} + +namespace bridges_remote { + +void acquireRemote2RemoteStub( remote_Interface *pThis ) +{ + Remote2RemoteStub *p = ( Remote2RemoteStub * ) pThis; + if( 1 == osl_incrementInterlockedCount( &(p->m_nRef) ) ) + { + p->m_pEnvRemote->pExtEnv->registerProxyInterface( + p->m_pEnvRemote->pExtEnv, + (void**)&pThis, + freeRemote2RemoteStub, + p->m_sOid.pData, + p->m_pType ); + OSL_ASSERT( (remote_Interface *)p == pThis ); + } +} + +void freeRemote2RemoteStub(uno_ExtEnvironment *, void * stub) { + delete static_cast< Remote2RemoteStub * >(stub); +} + +Remote2RemoteStub::Remote2RemoteStub( rtl_uString *pOid, + typelib_InterfaceTypeDescription *pType, + uno_Environment *pEnvRemote, + requestClientSideDispatcher dispatch ) : + m_sOid( pOid ), + m_pType( (typelib_InterfaceTypeDescription * ) pType ), + m_nRef( 1 ), + m_pEnvRemote( pEnvRemote ), + m_dispatch( dispatch ), + m_nReleaseRemote( 1 ) +{ + typelib_typedescription_acquire( ( typelib_TypeDescription * ) m_pType ); + m_pEnvRemote->acquire( m_pEnvRemote ); + + acquire = acquireRemote2RemoteStub; + release = thisRelease; + pDispatcher = thisDispatch; +#if OSL_DEBUG_LEVEL > 1 + thisCounter.acquire(); +#endif +} + +Remote2RemoteStub::~Remote2RemoteStub() +{ + + // send a release via the connection ! + sal_Bool bNeedsRelease = sal_False; + if( ! m_pType->aBase.bComplete ) + { + // m_pType may be exchanged during complete, so it needs to be acquired + // (MT : Another thread may use m_pType during e.g. dispatch ! ). + typelib_typedescription_acquire( (typelib_TypeDescription*)m_pType ); + bNeedsRelease = sal_True; + typelib_typedescription_complete( (typelib_TypeDescription **) &m_pType ); + } + + uno_Any any; + uno_Any *pAny = &any; + + typelib_TypeDescription *pReleaseMethod = 0; + typelib_typedescriptionreference_getDescription( + &pReleaseMethod , + m_pType->ppAllMembers[REMOTE_RELEASE_METHOD_INDEX] ); + for( int i = 0 ; i < m_nReleaseRemote ; i ++ ) + { + thisDispatch( this, + pReleaseMethod, + 0, + 0, + &pAny ); + } + typelib_typedescription_release( pReleaseMethod ); + if( bNeedsRelease ) + { + typelib_typedescription_release( (typelib_TypeDescription * ) m_pType ); + } + + typelib_typedescription_release( (typelib_TypeDescription * ) m_pType ); + m_pEnvRemote->release( m_pEnvRemote ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.release(); +#endif +} + +void Remote2RemoteStub::releaseRemote() +{ + osl_incrementInterlockedCount( &m_nReleaseRemote ); +} + +} // end namespace bridges_remote diff --git a/bridges/source/remote/static/remote_types.cxx b/bridges/source/remote/static/remote_types.cxx new file mode 100644 index 000000000000..0be511c987b0 --- /dev/null +++ b/bridges/source/remote/static/remote_types.cxx @@ -0,0 +1,96 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include "remote_types.hxx" + +namespace bridges_remote { + +sal_Bool SAL_CALL remote_relatesToInterface2( typelib_TypeDescription * pTypeDescr ) +{ + switch (pTypeDescr->eTypeClass) + { + case typelib_TypeClass_SEQUENCE: + { + switch (((typelib_IndirectTypeDescription *)pTypeDescr)->pType->eTypeClass) + { + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pTD = 0; + TYPELIB_DANGER_GET( &pTD, ((typelib_IndirectTypeDescription *)pTypeDescr)->pType ); + sal_Bool bRel = remote_relatesToInterface( pTD ); + TYPELIB_DANGER_RELEASE( pTD ); + return bRel; + } + default: + break; + } + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + // ...optimized... to avoid getDescription() calls! + typelib_CompoundTypeDescription * pComp = (typelib_CompoundTypeDescription *)pTypeDescr; + typelib_TypeDescriptionReference ** pTypes = pComp->ppTypeRefs; + for ( sal_Int32 nPos = pComp->nMembers; nPos--; ) + { + switch (pTypes[nPos]->eTypeClass) + { + case typelib_TypeClass_INTERFACE: + case typelib_TypeClass_UNION: // might relate to interface + case typelib_TypeClass_ANY: // might relate to interface + return sal_True; + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_TypeDescription * pTD = 0; + TYPELIB_DANGER_GET( &pTD, pTypes[nPos] ); + sal_Bool bRel = remote_relatesToInterface( pTD ); + TYPELIB_DANGER_RELEASE( pTD ); + if (bRel) + return sal_True; + break; + } + default: + break; + } + } + if (pComp->pBaseTypeDescription) + return remote_relatesToInterface( (typelib_TypeDescription *)pComp->pBaseTypeDescription ); + break; + } + default: + OSL_ASSERT( 0 ); + } + return sal_False; +} + +} diff --git a/bridges/source/remote/static/remote_types.hxx b/bridges/source/remote/static/remote_types.hxx new file mode 100644 index 000000000000..bb7a908a01f9 --- /dev/null +++ b/bridges/source/remote/static/remote_types.hxx @@ -0,0 +1,89 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _BRIDGES_REMOTE_TYPES_HXX_ +#define _BRIDGES_REMOTE_TYPES_HXX_ + +#include <osl/diagnose.h> +#include <sal/types.h> +#include <typelib/typedescription.h> + +namespace bridges_remote +{ + +inline sal_Bool SAL_CALL remote_relatesToInterface( typelib_TypeDescription *pTypeDescr ); +sal_Bool SAL_CALL remote_relatesToInterface2( typelib_TypeDescription * pTypeDescr ); + + +/** Determines whether given type might relate or relates to an interface, + i.e. values of this type are interface or may contain interface(s).<br> + @param pTypeDescr type description of type + @return true if type might relate to an interface, false otherwise +*/ +inline sal_Bool SAL_CALL remote_relatesToInterface( typelib_TypeDescription * pTypeDescr ) +{ + switch (pTypeDescr->eTypeClass) + { + case typelib_TypeClass_SEQUENCE: + switch (((typelib_IndirectTypeDescription *)pTypeDescr)->pType->eTypeClass) + { + case typelib_TypeClass_INTERFACE: + case typelib_TypeClass_UNION: // might relate to interface + case typelib_TypeClass_ANY: // might relate to interface + return sal_True; + case typelib_TypeClass_SEQUENCE: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + return remote_relatesToInterface2( pTypeDescr ); + default: + return sal_False; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + return remote_relatesToInterface2( pTypeDescr ); + case typelib_TypeClass_UNION: // might relate to interface + case typelib_TypeClass_ANY: // might relate to interface + case typelib_TypeClass_INTERFACE: + return sal_True; + default: + return sal_False; + } +} + +/** Determines whether given type is a cpp simple type, e.g. int, enum.<br> + @param pTypeDescr type description of type + @return true if type is a cpp simple type, false otherwise +*/ +inline sal_Bool SAL_CALL remote_isSimpleType( typelib_TypeDescription * pTypeDescr ) +{ + return (pTypeDescr->eTypeClass <= typelib_TypeClass_ENUM && + pTypeDescr->eTypeClass != typelib_TypeClass_STRING && + pTypeDescr->eTypeClass != typelib_TypeClass_ANY && + pTypeDescr->eTypeClass != typelib_TypeClass_TYPE); +} + +} +#endif diff --git a/bridges/source/remote/static/stub.cxx b/bridges/source/remote/static/stub.cxx new file mode 100644 index 000000000000..ec276c801862 --- /dev/null +++ b/bridges/source/remote/static/stub.cxx @@ -0,0 +1,336 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <sal/alloca.h> +#include <osl/diagnose.h> + +#include <uno/data.h> +#include <uno/mapping.hxx> + +#include <bridges/remote/stub.hxx> +#include <bridges/remote/proxy.hxx> +#include <bridges/remote/context.h> +#include <bridges/remote/bridgeimpl.hxx> + +#include "remote_types.hxx" + +#if OSL_DEBUG_LEVEL > 1 +#include <bridges/remote/counter.hxx> +static MyCounter thisCounter( "DEBUG : Uno2RemoteStub"); +#endif + +using namespace ::com::sun::star::uno; +using namespace bridges_remote; + +extern "C" { + +void SAL_CALL thisRelease( remote_Interface *pThis ) +{ + Uno2RemoteStub *p = ( Uno2RemoteStub * ) pThis; + if (! osl_decrementInterlockedCount( &(p->m_nRef) )) + { + p->m_pEnvRemote->pExtEnv->revokeInterface( p->m_pEnvRemote->pExtEnv, pThis ); + } +} + +void SAL_CALL thisDispatch( + remote_Interface * pRemoteI, + typelib_TypeDescription const * pType, + void * pReturn, + void * ppArgs[], + uno_Any ** ppException ) +{ + Uno2RemoteStub *p = ( Uno2RemoteStub * ) pRemoteI; + + RemoteThreadCounter counter( p->m_pEnvRemote ); + + typelib_InterfaceMethodTypeDescription *pMethodType = 0; + typelib_InterfaceAttributeTypeDescription *pAttributeType = 0; + typelib_TypeDescription *pReturnType = 0; + typelib_TypeDescription **ppArgType = 0; + sal_Int32 nArgCount = 0; + sal_Bool *pbIsIn = 0; + sal_Bool *pbIsOut = 0; + sal_Bool bConversionNeededForReturn = sal_False; + sal_Bool *pbConversionNeeded = 0; + + sal_Int32 i; + //-------------------------------- + // Collect all needed types ! + //-------------------------------- + if( typelib_TypeClass_INTERFACE_ATTRIBUTE == pType->eTypeClass ) + { + pAttributeType = ( typelib_InterfaceAttributeTypeDescription * ) pType; + if( pReturn ) + { + TYPELIB_DANGER_GET( &pReturnType , pAttributeType->pAttributeTypeRef ); + bConversionNeededForReturn = remote_relatesToInterface( pReturnType ); + } + else + { + nArgCount = 1; + ppArgType = (typelib_TypeDescription **) alloca( sizeof( void * ) ); + pbIsIn = ( sal_Bool * ) alloca( sizeof( sal_Bool ) ); + pbIsOut = ( sal_Bool * ) alloca( sizeof( sal_Bool ) ); + pbConversionNeeded = ( sal_Bool * ) alloca( sizeof( sal_Bool ) ); + pbIsIn[0] = sal_True; + pbIsOut[0] = sal_False; + ppArgType[0] = 0; + TYPELIB_DANGER_GET( &( ppArgType[0] ) , pAttributeType->pAttributeTypeRef ); + pbConversionNeeded[0] = remote_relatesToInterface( ppArgType[0] ); + } + } + if( typelib_TypeClass_INTERFACE_METHOD == pType->eTypeClass ) + { + pMethodType = ( typelib_InterfaceMethodTypeDescription * ) pType; + TYPELIB_DANGER_GET( &pReturnType , pMethodType->pReturnTypeRef ); + bConversionNeededForReturn = remote_relatesToInterface( pReturnType ); + nArgCount = pMethodType->nParams; + ppArgType = (typelib_TypeDescription **) alloca( sizeof( void * ) * nArgCount ); + pbIsIn = (sal_Bool * ) alloca( sizeof( sal_Bool ) * nArgCount ); + pbIsOut = (sal_Bool * ) alloca( sizeof( sal_Bool ) * nArgCount ); + pbConversionNeeded = ( sal_Bool * ) alloca( sizeof( sal_Bool ) * nArgCount ); + + for( i = 0 ; i < nArgCount ; i ++ ) + { + ppArgType[i] = 0; + TYPELIB_DANGER_GET( & (ppArgType[i]) , pMethodType->pParams[i].pTypeRef ); + pbIsIn[i] = pMethodType->pParams[i].bIn; + pbIsOut[i] = pMethodType->pParams[i].bOut; + pbConversionNeeded[i] = remote_relatesToInterface( ppArgType[i] ); + } + } + + // create Mapping + + void *pUnoReturn = 0; + void **ppUnoArgs = 0; + + if( pReturnType ) + { + if( bConversionNeededForReturn ) + { + pUnoReturn = alloca( pReturnType->nSize ); + } + else + { + pUnoReturn = pReturn; + } + } + + ppUnoArgs = (void **) alloca( nArgCount * sizeof( void * ) ); + for( i = 0 ; i < nArgCount ; i ++ ) + { + if( pbConversionNeeded[i] ) + { + ppUnoArgs[i] = alloca( ppArgType[i]->nSize ); + if( pbIsIn[i] ) + { + uno_copyAndConvertData( + ppUnoArgs[i], + ppArgs[i], + ppArgType[i], + p->m_mapRemote2Uno.get() + ); + } + } + else + { + ppUnoArgs[i] = ppArgs[i]; + } + } + + // do the call + uno_Any any; + uno_Any *pAny = &any; + + p->m_pUnoI->pDispatcher( p->m_pUnoI, + pType, + pUnoReturn, + ppUnoArgs, + &pAny); + + if( ! pAny ) + { + // ------------------ + // No Exception + // ------------------ + + // Map return value + if( pReturnType && bConversionNeededForReturn ) + { + uno_copyAndConvertData( + pReturn , + pUnoReturn, + pReturnType, + p->m_mapUno2Remote.get() ); + uno_destructData( pUnoReturn , pReturnType, 0 ); + } + + // map arguments + for( i = 0 ; i < nArgCount ; i ++ ) + { + if( pbConversionNeeded[i] ) + { + if( pbIsIn[i] ) { + if( pbIsOut[i] ) { + uno_destructData( + ppArgs[i] , + ppArgType[i] , + remote_release ); + uno_copyAndConvertData( ppArgs[i] , + ppUnoArgs[i], + ppArgType[i], + p->m_mapUno2Remote.get() ); + } + } + else // pure out + { + uno_copyAndConvertData( ppArgs[i] , + ppUnoArgs[i], + ppArgType[i], + p->m_mapUno2Remote.get() ); + } + uno_destructData( ppUnoArgs[i], + ppArgType[i], + 0 ); + } + } + *ppException = 0; + } + else + { + // ----------------------- + // an exception occured + // ----------------------- + typelib_TypeDescription *pAnyType = 0; + getCppuType( (Any*) 0 ).getDescription( &pAnyType ); + uno_copyAndConvertData( *ppException , + pAny , + pAnyType, + p->m_mapUno2Remote.get() ); + uno_destructData( pAny , pAnyType , 0 ); + typelib_typedescription_release( pAnyType ); + + // destruct uno in parameters ( out parameters have not been constructed ) + for( i = 0 ; i < nArgCount ; i ++ ) + { + if( pbConversionNeeded[i] && pbIsIn[i] ) + { + uno_destructData( ppUnoArgs[i], + ppArgType[i], + 0 ); + } + } + } + + //-------------------------- + // release all acquired types + //-------------------------- + if( pReturnType ) + { + TYPELIB_DANGER_RELEASE( pReturnType ); + } + for( i = 0 ; i < nArgCount ; i ++ ) + { + TYPELIB_DANGER_RELEASE( ppArgType[ i] ); + } +} + +} + +namespace bridges_remote { + +void acquireUno2RemoteStub( remote_Interface *pThis ) +{ + Uno2RemoteStub *p = ( Uno2RemoteStub * ) pThis; + if( 1 == osl_incrementInterlockedCount( &(p->m_nRef) ) ) + { + + p->m_pEnvRemote->pExtEnv->registerProxyInterface( + p->m_pEnvRemote->pExtEnv, + (void**)&pThis, + freeUno2RemoteStub, + p->m_sOid.pData, + p->m_pType ); + + OSL_ASSERT( (remote_Interface*) p == pThis ); + } +} + +void freeUno2RemoteStub(uno_ExtEnvironment *, void * stub) { + delete static_cast< Uno2RemoteStub * >(stub); +} + +Uno2RemoteStub::Uno2RemoteStub( uno_Interface *pUnoI, + rtl_uString *pOid, + typelib_InterfaceTypeDescription *pType, + uno_Environment *pEnvUno, + uno_Environment *pEnvRemote ) : + m_sOid( pOid ), + m_pType( pType ), + m_pUnoI( pUnoI ), + m_nRef( 1 ), + m_pEnvUno( pEnvUno ), + m_pEnvRemote( pEnvRemote ), + m_mapRemote2Uno( pEnvRemote, pEnvUno ), + m_mapUno2Remote( pEnvUno, pEnvRemote ) +{ + typelib_typedescription_acquire( (typelib_TypeDescription * )m_pType ); + m_pEnvUno->acquire( m_pEnvUno ); + m_pEnvRemote->acquire( m_pEnvRemote ); + + acquire = acquireUno2RemoteStub; + release = thisRelease; + pDispatcher = thisDispatch; + + m_pEnvUno->pExtEnv->registerInterface( m_pEnvUno->pExtEnv, + (void **)&m_pUnoI, + m_sOid.pData, + m_pType ); + m_pUnoI->acquire( m_pUnoI ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.acquire(); +#endif +} + +Uno2RemoteStub::~Uno2RemoteStub() +{ + m_pEnvUno->pExtEnv->revokeInterface( m_pEnvUno->pExtEnv , m_pUnoI ); + + typelib_typedescription_release( (typelib_TypeDescription * )m_pType ); + m_pUnoI->release( m_pUnoI ); + m_pEnvUno->release( m_pEnvUno ); + m_pEnvRemote->release( m_pEnvRemote ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.release(); +#endif +} + +} // end namespace bridges_remote diff --git a/bridges/source/remote/urp/makefile.mk b/bridges/source/remote/urp/makefile.mk new file mode 100644 index 000000000000..eaa3f3a6f146 --- /dev/null +++ b/bridges/source/remote/urp/makefile.mk @@ -0,0 +1,78 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/..$/.. + +PRJNAME=bridges +TARGET=urp_uno +ENABLE_EXCEPTIONS=TRUE +USE_DEFFILE=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# ------------------------------------------------------------------ + +SLOFILES= \ + $(SLO)$/urp_environment.obj \ + $(SLO)$/urp_marshal.obj \ + $(SLO)$/urp_unmarshal.obj \ + $(SLO)$/urp_dispatch.obj \ + $(SLO)$/urp_job.obj \ + $(SLO)$/urp_reader.obj \ + $(SLO)$/urp_writer.obj \ + $(SLO)$/urp_log.obj \ + $(SLO)$/urp_bridgeimpl.obj \ + $(SLO)$/urp_propertyobject.obj \ + $(SLO)$/urp_threadid.obj + +.IF "$(COM)"=="GCC" +NOOPTFILES= \ + $(SLO)$/urp_reader.obj +.ENDIF # "$(COM)"=="GCC" + +SHL1TARGET= $(TARGET) + +SHL1DEF=$(MISC)$/$(SHL1TARGET).def +SHL1VERSIONMAP=..$/..$/bridge_exports.map +SHL1RPATH=URELIB + +SHL1STDLIBS=\ + $(SALLIB)\ + $(CPPULIB) + +SHL1LIBS=\ + $(SLB)$/$(TARGET).lib \ + $(SLB)$/bridges_remote_static.lib + +DEF1NAME= $(SHL1TARGET) + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + diff --git a/bridges/source/remote/urp/urp_bridgeimpl.cxx b/bridges/source/remote/urp/urp_bridgeimpl.cxx new file mode 100644 index 000000000000..af619c8f3c35 --- /dev/null +++ b/bridges/source/remote/urp/urp_bridgeimpl.cxx @@ -0,0 +1,250 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <osl/thread.h> +#include <bridges/remote/helper.hxx> + +#include <algorithm> + +#include "urp_bridgeimpl.hxx" + +using namespace ::rtl; +using namespace ::osl; +using namespace ::com::sun::star::uno; +namespace bridges_urp +{ + +template < class t > +inline t mymin( const t & val1, const t & val2 ) +{ + return val1 < val2 ? val1 : val2; +} + +/*********** + * urp_BridgeImpl + ***********/ +urp_BridgeImpl::urp_BridgeImpl( sal_Int32 nCacheSize , sal_uInt32 nInitialMarshalerSize ) : + m_blockMarshaler( this , nInitialMarshalerSize , ::bridges_remote::remote_retrieveOidFromProxy), + m_nMarshaledMessages( 0 ), + m_oidCacheOut( (sal_uInt16)nCacheSize ), + m_tidCacheOut( (sal_uInt16)nCacheSize ), + m_typeCacheOut( (sal_uInt16)nCacheSize ) +{ + m_pOidIn = new OUString[ nCacheSize ]; + m_pTidIn = new ByteSequence[ nCacheSize ]; + m_pTypeIn = new Type[ nCacheSize ]; + m_nRemoteThreads = 0; +} + +urp_BridgeImpl::~urp_BridgeImpl() +{ + delete [] m_pOidIn; + delete [] m_pTidIn; + delete [] m_pTypeIn; +} + + +void urp_BridgeImpl::applyProtocolChanges( const Properties &props ) +{ + if( m_properties.nTypeCacheSize != props.nTypeCacheSize ) + { + if( props.nTypeCacheSize == 0 ) + { + delete [] m_pTypeIn; + m_pTypeIn = 0; + } + else + { + Type *pNew = new Type[props.nTypeCacheSize]; + sal_Int32 i; + sal_Int32 iMin = mymin( m_properties.nTypeCacheSize , props.nTypeCacheSize ); + for( i = 0; i < iMin ; i ++ ) + { + pNew[i] = m_pTypeIn[i]; + } + delete [] m_pTypeIn; + m_pTypeIn = pNew; + } + OSL_ASSERT( props.nTypeCacheSize <= 0xffff ); + m_properties.nTypeCacheSize = props.nTypeCacheSize; + m_typeCacheOut.resize( (sal_uInt16)props.nTypeCacheSize ); + } + + if( m_properties.nOidCacheSize != props.nOidCacheSize ) + { + if( 0 == props.nOidCacheSize ) + { + delete [] m_pOidIn; + m_pOidIn = 0; + } + else + { + OUString *pNew = new OUString[props.nOidCacheSize]; + sal_Int32 i; + sal_Int32 iMin = mymin( m_properties.nOidCacheSize , props.nOidCacheSize ); + for( i = 0; i < iMin ; i ++ ) + { + pNew[i] = m_pOidIn[i]; + } + delete [] m_pOidIn; + m_pOidIn = pNew; + } + OSL_ASSERT( props.nOidCacheSize <= 0xffff ); + m_oidCacheOut.resize( (sal_uInt16)props.nOidCacheSize ); + m_properties.nOidCacheSize = props.nOidCacheSize; + } + + if( m_properties.nTidCacheSize != props.nTidCacheSize ) + { + if( 0 == props.nTidCacheSize ) + { + delete [] m_pTidIn; + m_pTidIn = 0; + } + else + { + ByteSequence *pNew = new ByteSequence[props.nTidCacheSize]; + sal_Int32 i; + sal_Int32 iMin = mymin( m_properties.nTidCacheSize , props.nTidCacheSize ); + for( i = 0; i < iMin ; i ++ ) + { + pNew[i] = m_pTidIn[i]; + } + delete [] m_pTidIn; + m_pTidIn = pNew; + } + OSL_ASSERT( props.nTidCacheSize <= 0xffff ); + m_tidCacheOut.resize( (sal_uInt16)props.nTidCacheSize ); + m_properties.nTidCacheSize = props.nTidCacheSize; + } + + if( m_properties.sVersion != props.sVersion ) + { + m_properties.sVersion = props.sVersion; + } + + if( m_properties.nFlushBlockSize != props.nFlushBlockSize ) + { + m_properties.nFlushBlockSize = props.nFlushBlockSize; + } + + if( m_properties.nOnewayTimeoutMUSEC != props.nOnewayTimeoutMUSEC ) + { + m_properties.nOnewayTimeoutMUSEC = props.nOnewayTimeoutMUSEC; + } + + if( props.bClearCache ) + { + if( m_properties.nTypeCacheSize ) + { + delete [] m_pTypeIn; + m_pTypeIn = new Type[m_properties.nTypeCacheSize]; + m_typeCacheOut.clear(); + } + m_lastInType = Type(); + m_lastOutType = Type(); + + if( m_properties.nOidCacheSize ) + { + delete [] m_pOidIn; + m_pOidIn = new OUString[ m_properties.nOidCacheSize]; + m_oidCacheOut.clear(); + } + m_lastOutOid = OUString(); + m_lastInOid = OUString(); + + if( m_properties.nTidCacheSize ) + { + delete [] m_pTidIn; + m_pTidIn = new ByteSequence[m_properties.nTidCacheSize]; + m_tidCacheOut.clear(); + } + m_lastInTid = ByteSequence(); + m_lastOutTid = ByteSequence(); + } + + if( m_properties.bNegotiate != props.bNegotiate ) + { + m_properties.bNegotiate = props.bNegotiate; + } + + if( m_properties.bForceSynchronous != props.bForceSynchronous ) + { + m_properties.bForceSynchronous = props.bForceSynchronous; + } + + m_properties.bCurrentContext = props.bCurrentContext; +} + +void urp_BridgeImpl::addError( char const *pError ) +{ + OUString message = OUString( RTL_CONSTASCII_USTRINGPARAM( "(tid=" ) ); + message += OUString::valueOf( (sal_Int32 ) osl_getThreadIdentifier( 0 ) ); + message += OUString::createFromAscii( ") " ); + message += OUString::createFromAscii( pError ); + MutexGuard guard( m_errorListMutex ); + m_lstErrors.push_back( message ); +} + +void urp_BridgeImpl::addError( const OUString & error ) +{ + OUString message = OUString( RTL_CONSTASCII_USTRINGPARAM( "(tid=" ) ); + message += OUString::valueOf( (sal_Int32 ) osl_getThreadIdentifier( 0 ) ); + message += OUString::createFromAscii( ") " ); + message += error; + MutexGuard guard( m_errorListMutex ); + m_lstErrors.push_back( message ); +} + +void urp_BridgeImpl::dumpErrors( FILE * f) +{ + MutexGuard guard( m_errorListMutex ); + for( ::std::list< OUString >::iterator ii = m_lstErrors.begin() ; + ii != m_lstErrors.end() ; + ++ii ) + { + OString o = OUStringToOString( *ii , RTL_TEXTENCODING_UTF8 ); + fprintf( f, "%s\n" , o.getStr() ); + } +} + +OUString urp_BridgeImpl::getErrorsAsString( ) +{ + MutexGuard guard( m_errorListMutex ); + OUString ret; + for( ::std::list< OUString >::iterator ii = m_lstErrors.begin() ; + ii != m_lstErrors.end() ; + ++ii ) + { + ret += *ii; + } + return ret; +} + +} diff --git a/bridges/source/remote/urp/urp_bridgeimpl.hxx b/bridges/source/remote/urp/urp_bridgeimpl.hxx new file mode 100644 index 000000000000..53d583bed48d --- /dev/null +++ b/bridges/source/remote/urp/urp_bridgeimpl.hxx @@ -0,0 +1,133 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _URP_BRIDGEIMPL_HXX_ +#define _URP_BRIDGEIMPL_HXX_ + +#include <stdio.h> +#include <osl/mutex.hxx> +#include <osl/conditn.hxx> +#include <rtl/ustring.hxx> +#include <rtl/byteseq.hxx> + +#ifndef _UNO_THREADPOOL_H_ +#include <uno/threadpool.h> +#endif +#include <bridges/remote/bridgeimpl.hxx> + +#ifndef _URP_CACHE_HXX_ +#include "urp_cache.hxx" +#endif +#include "urp_marshal_decl.hxx" + +#ifndef _URP_REPLYCONTAINER_HXX_ +#include "urp_replycontainer.hxx" +#endif +#include "urp_property.hxx" + + +namespace bridges_urp +{ + +class PropertyObject; + +struct equalOUString +{ + sal_Int32 operator() ( const ::rtl::OUString &s1, const ::rtl::OUString &s2 ) const + { + return s1 == s2; + } +}; + +struct equalType +{ + sal_Int32 operator() ( const ::com::sun::star::uno::Type &t1, + const ::com::sun::star::uno::Type &t2 ) const + { + return t1 == t2; + } +}; + +class OWriterThread; +class OReaderThread; + +struct urp_BridgeImpl : + public remote_BridgeImpl +{ + urp_BridgeImpl( sal_Int32 nCacheSize , sal_uInt32 nInitialMarshalerSize ); + ~urp_BridgeImpl(); + + void applyProtocolChanges( const Properties & ); + + void startBlockBridge(); + void stopBlockBridge(); + void addError( char const *pError ); + void addError( const ::rtl::OUString &anError ); + void dumpErrors( FILE *f ); + ::rtl::OUString getErrorsAsString(); + + ::osl::Mutex m_marshalingMutex; + ::osl::Mutex m_disposingMutex; + ::osl::Mutex m_errorListMutex; + Marshal m_blockMarshaler; + sal_Int32 m_nMarshaledMessages; + + // Caches for vars, that go from local process to the remote process + Cache < ::rtl::OUString , equalOUString > m_oidCacheOut; + Cache < ::rtl::ByteSequence , EqualThreadId > m_tidCacheOut; + Cache < ::com::sun::star::uno::Type , equalType > m_typeCacheOut; + + ::com::sun::star::uno::Type m_lastOutType; + ::rtl::ByteSequence m_lastOutTid; + ::rtl::OUString m_lastOutOid; + + // Caches for vars, that come from the remote process to the local process + ::rtl::OUString *m_pOidIn; + ::rtl::ByteSequence *m_pTidIn; + ::com::sun::star::uno::Type *m_pTypeIn; + + ::com::sun::star::uno::Type m_lastInType; + ::rtl::ByteSequence m_lastInTid; + ::rtl::OUString m_lastInOid; + + urp_ClientJobContainer m_clientJobContainer; + + OWriterThread *m_pWriter; + OReaderThread *m_pReader; + ::rtl::OString m_sLogFileName; + FILE *m_pLogFile; + ::osl::Condition m_initialized; + ::osl::Condition m_cndWaitForThreads; + + struct Properties m_properties; + class PropertyObject *m_pPropertyObject; + ::std::list< ::rtl::OUString > m_lstErrors; + uno_ThreadPool m_hThreadPool; +}; + + +} +#endif diff --git a/bridges/source/remote/urp/urp_cache.h b/bridges/source/remote/urp/urp_cache.h new file mode 100644 index 000000000000..fa06453ef524 --- /dev/null +++ b/bridges/source/remote/urp/urp_cache.h @@ -0,0 +1,57 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + + +namespace bridges_urp +{ + template < class t , class tequals > + class Cache + { + public: + inline Cache ( sal_uInt16 nMaxEntries ); + inline ~Cache(); + + // puts the value t into the cache. Returns then entry, + // that is used for this value. + inline sal_uInt16 put( const t & ); + + // lookup, if there is an entry for this value + // returns 0xffff, when value cannot be found in the list + inline sal_uInt16 seek( const t & ); + + // resizes the cache, conserving overlapping values + inline void resize( sal_uInt16 nNewMaxEntries ); + + // empties the cache + inline void clear(); + private: + t *m_pCache; + ::std::list< sal_uInt16 > m_lstLeastRecentlyUsed; + sal_uInt16 m_nMaxEntries; + sal_uInt16 m_nEntries; + }; +} diff --git a/bridges/source/remote/urp/urp_cache.hxx b/bridges/source/remote/urp/urp_cache.hxx new file mode 100644 index 000000000000..aa366ddaeca7 --- /dev/null +++ b/bridges/source/remote/urp/urp_cache.hxx @@ -0,0 +1,160 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <stdio.h> +#include <list> +#include <algorithm> +#include <rtl/ustring.hxx> + +#include "urp_threadid.hxx" +#include "urp_cache.h" + +namespace bridges_urp +{ + + template < class t , class tequals > + inline Cache< t , tequals >::Cache( sal_uInt16 nMaxEntries ) : + m_pCache( new t[nMaxEntries] ), + m_nMaxEntries( nMaxEntries ), + m_nEntries( 0 ) + { + + } + + template < class t , class tequals > + inline Cache< t , tequals >::~Cache( ) + { + delete [] m_pCache; + } + + + template < class t , class tequals > + inline sal_uInt16 Cache< t , tequals >::put( const t & value ) + { + if( ! m_nMaxEntries ) + { + return 0xffff; + } + sal_uInt16 nEntry = 0xffff; + if( m_nEntries < m_nMaxEntries ) + { + // cache has still empty places + m_pCache[m_nEntries] = value; + nEntry = m_nEntries; + m_nEntries ++; + + // add it to the cache + m_lstLeastRecentlyUsed.push_front( nEntry ); + } + else + { + // cache is full, remove an element and insert the new one + nEntry = m_lstLeastRecentlyUsed.back(); + m_lstLeastRecentlyUsed.pop_back(); + m_lstLeastRecentlyUsed.push_front( nEntry ); + + m_pCache[nEntry] = value; + } + return nEntry; + } + + template < class t , class tequals > + inline sal_uInt16 Cache< t , tequals >::seek( const t & value ) + { + for( ::std::list< sal_uInt16 >::iterator ii = m_lstLeastRecentlyUsed.begin() ; + ii != m_lstLeastRecentlyUsed.end() ; + ++ ii ) + { + if( value == m_pCache[*ii] ) + { + sal_uInt16 nEntry = *ii; + m_lstLeastRecentlyUsed.erase( ii ); + m_lstLeastRecentlyUsed.push_front( nEntry ); + return nEntry; + } + } + return 0xffff; + } + + // helper predicate for element removal + template < class t > + struct PredicateOverMax + { + t m_; + inline PredicateOverMax( const t &value ) : m_(value) + {} + sal_Int32 operator () ( const t &value ) const + { return value >= m_; } + }; + + template < class t, class tequals > + inline void Cache < t , tequals >::resize( sal_uInt16 nNewMaxEntries ) + { + if( 0 == nNewMaxEntries ) + { + m_lstLeastRecentlyUsed.clear(); + delete [] m_pCache; + m_pCache = 0; + m_nMaxEntries = 0; + } + else + { + // allocate + t *pNew = new t[nNewMaxEntries]; + sal_Int32 nMin = nNewMaxEntries < m_nMaxEntries ? nNewMaxEntries : m_nMaxEntries; + + // copy + for( sal_Int32 i = 0; i < nMin ; i ++ ) + { + pNew[i] = m_pCache[i]; + } + // delete + delete [] m_pCache; + + // assign + m_pCache = pNew; + + // remove overlapping lru cache entries + ::std::remove_if(m_lstLeastRecentlyUsed.begin(), + m_lstLeastRecentlyUsed.end(), + PredicateOverMax< sal_Int32 > ( nMin ) ); + } + m_nMaxEntries = nNewMaxEntries; + m_nEntries = m_nEntries < m_nMaxEntries ? + m_nEntries : m_nMaxEntries; + } + + template < class t, class tequals > + inline void Cache < t, tequals >:: clear() + { + for( sal_Int32 i = 0; i < m_nMaxEntries ; i ++ ) + { + m_pCache[i] = t(); + } + m_lstLeastRecentlyUsed.clear(); + m_nEntries = 0; + } +} diff --git a/bridges/source/remote/urp/urp_dispatch.cxx b/bridges/source/remote/urp/urp_dispatch.cxx new file mode 100644 index 000000000000..ae9f3dff9d54 --- /dev/null +++ b/bridges/source/remote/urp/urp_dispatch.cxx @@ -0,0 +1,116 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <sal/alloca.h> +#include <osl/mutex.hxx> +#include <osl/diagnose.h> + +#include <rtl/alloc.h> +#include <rtl/ustrbuf.hxx> + +#include <uno/mapping.hxx> +#include <uno/threadpool.h> + +#include <bridges/remote/remote.h> +#include <bridges/remote/stub.hxx> +#include <bridges/remote/proxy.hxx> +#include <bridges/remote/remote.hxx> + +#include "urp_bridgeimpl.hxx" +#include "urp_marshal.hxx" +#include "urp_dispatch.hxx" +#include "urp_job.hxx" +#include "urp_writer.hxx" +#include "urp_log.hxx" + +using namespace ::rtl; +using namespace ::osl; +using namespace ::com::sun::star::uno; + +namespace bridges_urp +{ + +void SAL_CALL urp_sendCloseConnection( uno_Environment *pEnvRemote ) +{ + remote_Context *pContext = (remote_Context *) pEnvRemote->pContext; + urp_BridgeImpl *pImpl = (urp_BridgeImpl*) ( pContext->m_pBridgeImpl ); + + { + MutexGuard guard( pImpl->m_marshalingMutex ); + + // send immediately + if( ! pImpl->m_blockMarshaler.empty() ) + { + pImpl->m_pWriter->touch( sal_True ); + } + + pImpl->m_pWriter->sendEmptyMessage(); + } +} +extern "C" void SAL_CALL urp_sendRequest( + uno_Environment *pEnvRemote, + typelib_TypeDescription const * pMemberType, + rtl_uString *pOid, + typelib_InterfaceTypeDescription *pInterfaceType, + void *pReturn, + void *ppArgs[], + uno_Any **ppException ) +{ + remote_Context *pContext = (remote_Context *) pEnvRemote->pContext; + urp_BridgeImpl *pImpl = (urp_BridgeImpl*) ( pContext->m_pBridgeImpl ); + pImpl->m_initialized.wait(); + urp_sendRequest_internal( + pEnvRemote, pMemberType, pOid, pInterfaceType, pReturn, ppArgs, + ppException ); +} +void SAL_CALL urp_sendRequest_internal( + uno_Environment *pEnvRemote, + typelib_TypeDescription const * pMemberType, + rtl_uString *pOid, + typelib_InterfaceTypeDescription *pInterfaceType, + void *pReturn, + void *ppArgs[], + uno_Any **ppException ) +{ + remote_Context *pContext = (remote_Context *) pEnvRemote->pContext; + urp_BridgeImpl *pImpl = (urp_BridgeImpl*) ( pContext->m_pBridgeImpl ); + + ClientJob job( + pEnvRemote, pContext, pImpl, pOid, pMemberType, pInterfaceType, pReturn, + ppArgs, ppException); + + if( job.pack() && ! job.isOneway() ) + { + job.wait(); + } +} + +} + + diff --git a/bridges/source/remote/urp/urp_dispatch.hxx b/bridges/source/remote/urp/urp_dispatch.hxx new file mode 100644 index 000000000000..2f14d89f75c2 --- /dev/null +++ b/bridges/source/remote/urp/urp_dispatch.hxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include <rtl/ustring.hxx> + +#include <typelib/typedescription.h> + +#include <uno/any2.h> + + +typedef struct _uno_Environment uno_Environment; +struct remote_Interface; + + + +namespace bridges_urp { + + const sal_uInt8 HDRFLAG_LONGHEADER = 0x80; + const sal_uInt8 HDRFLAG_REQUEST = 0x40; + const sal_uInt8 HDRFLAG_NEWTYPE = 0x20; + const sal_uInt8 HDRFLAG_NEWOID = 0x10; + const sal_uInt8 HDRFLAG_NEWTID = 0x08; + const sal_uInt8 HDRFLAG_LONGMETHODID = 0x04; + const sal_uInt8 HDRFLAG_IGNORECACHE = 0x02; + const sal_uInt8 HDRFLAG_MOREFLAGS = 0x01; + const sal_uInt8 HDRFLAG_MUSTREPLY = 0x80; + const sal_uInt8 HDRFLAG_SYNCHRONOUS = 0x40; + + const sal_uInt8 HDRFLAG_EXCEPTION = 0x20; + + void SAL_CALL urp_sendCloseConnection( uno_Environment *pEnvRemote ); + + extern "C" void SAL_CALL urp_sendRequest( + uno_Environment *pEnvRemote, + typelib_TypeDescription const * pMemberType, + rtl_uString *pOid, + typelib_InterfaceTypeDescription *pInterfaceType, + void *pReturn, + void *ppArgs[], + uno_Any **ppException + ); + + void SAL_CALL urp_sendRequest_internal( + uno_Environment *pEnvRemote, + typelib_TypeDescription const * pMemberType, + rtl_uString *pOid, + typelib_InterfaceTypeDescription *pInterfaceType, + void *pReturn, + void *ppArgs[], + uno_Any **ppException + ); + +} + diff --git a/bridges/source/remote/urp/urp_environment.cxx b/bridges/source/remote/urp/urp_environment.cxx new file mode 100644 index 000000000000..1e4f2f3c805c --- /dev/null +++ b/bridges/source/remote/urp/urp_environment.cxx @@ -0,0 +1,551 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" + +#include <stdio.h> + +#include <osl/interlck.h> +#include <osl/diagnose.h> +#include <osl/conditn.h> +#include <osl/mutex.hxx> +#include <osl/process.h> + +#include <rtl/alloc.h> +#include <rtl/uuid.h> +#include <rtl/unload.h> + +#include <uno/environment.h> +#include <uno/lbnames.h> +#include <uno/mapping.hxx> +#include <uno/threadpool.h> + +#include <com/sun/star/uno/Sequence.hxx> + +#include <bridges/remote/proxy.hxx> +#include <bridges/remote/stub.hxx> +#include <bridges/remote/context.h> +#include <bridges/remote/mapping.hxx> +#include <bridges/remote/counter.hxx> +#include <bridges/remote/bridgeimpl.hxx> +#include <bridges/remote/helper.hxx> + +#include "urp_bridgeimpl.hxx" +#include "urp_writer.hxx" +#include "urp_reader.hxx" +#include "urp_dispatch.hxx" +#include "urp_log.hxx" +#include "urp_propertyobject.hxx" + +using namespace ::rtl; +using namespace ::osl; +using namespace ::com::sun::star::uno; + +namespace bridges_urp +{ +rtl_StandardModuleCount g_moduleCount = MODULE_COUNT_INIT; + +// static void dumpProperties( struct Properties *p ) +// { +// fprintf( stderr , "FlushBlockSize : %d\n" , p->nFlushBlockSize ); +// fprintf( stderr , "OnewayTimeoutMUSEC : %d\n" , p->nOnewayTimeoutMUSEC ); +// fprintf( stderr , "OidCacheSize : %d\n" , p->nOidCacheSize ); +// fprintf( stderr , "TypeCacheSize : %d\n" , p->nTypeCacheSize ); +// fprintf( stderr , "TidCacheSize : %d\n" , p->nTidCacheSize ); +// OString o = OUStringToOString( p->sSupportedVersions , RTL_TEXTENCODING_ASCII_US ); +// fprintf( stderr , "SupportedVersions : %s\n" , o.pData->buffer ); +// o = OUStringToOString( p->sVersion , RTL_TEXTENCODING_ASCII_US ); +// fprintf( stderr , "Version : %s\n" , o.pData->buffer ); +// fprintf( stderr , "SupportsMultipleSynchronous : %d\n" , p->bSupportsMultipleSynchronous ); +// fprintf( stderr , "SupportsMustReply : %d\n" , p->bSupportsMustReply ); +// fprintf( stderr , "SupportsSynchronous : %d\n" , p->bSupportsSynchronous ); +// } + +// PropertySetterThread +//------------------------------------ +class PropertySetterThread : public ::osl::Thread +{ + urp_BridgeImpl *m_pImpl; + ::rtl::OUString m_sProps; + uno_Environment *m_pEnvRemote; +public: + PropertySetterThread( uno_Environment *pEnvRemote, + urp_BridgeImpl *pImpl, + const ::rtl::OUString & props ) + : m_pImpl( pImpl ) + , m_sProps( props ) + , m_pEnvRemote( pEnvRemote ) + { + if (m_sProps.getLength() > 0) { + m_sProps += rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(",")); + } + m_sProps += rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM("CurrentContext=")); + // hold the environment in case all references are released before this + // thread terminates + m_pEnvRemote->acquire( pEnvRemote ); + } + ~PropertySetterThread() + { + m_pEnvRemote->release( m_pEnvRemote ); + } + + virtual void SAL_CALL run() + { + for (;;) + { + switch ( m_pImpl->m_pPropertyObject->localRequestChange( ) ) + { + case 1: + sal_Bool bExceptionThrown; + m_pImpl->m_pPropertyObject->localCommitChange( m_sProps , &bExceptionThrown ); + OSL_ENSURE( !bExceptionThrown, "properties were not set\n" ); + goto done; + case 0: + OSL_TRACE( "urp-bridge : remote-counterpart won the changing-the-protocol-race\n" ); + goto done; + } + } + done: + m_pImpl->m_initialized.set(); + } + virtual void SAL_CALL onTerminated() + { + delete this; + } +}; +//------------------------------------ + + +void test_cache() +{ + OUString a = OUString( RTL_CONSTASCII_USTRINGPARAM( "a" ) ); + OUString b = OUString( RTL_CONSTASCII_USTRINGPARAM( "b" ) ); + OUString c = OUString( RTL_CONSTASCII_USTRINGPARAM( "c" ) ); + Cache < OUString , equalOUString > cache ( 2 ); + + sal_Int32 n = cache.put( a ); + if (cache.seek( a ) != n) + { + OSL_ASSERT( false ); + } + OSL_ASSERT( 0 == n ); + + n = cache.put( b ); + OSL_ASSERT( 1 == n ); + + cache.put( c ); + + OSL_ASSERT( 0xffff == cache.seek( a ) ); + OSL_ASSERT( 1 == cache.seek( b ) ); + OSL_ASSERT( 0 == cache.seek( c ) ); + + OSL_ASSERT( 1 == cache.put( a ) ); + OSL_ASSERT( 0xffff == cache.seek( b) ); + OSL_ASSERT( 1 == cache.seek( a ) ); + OSL_ASSERT( 0 == cache.seek( c ) ); +} + +/******************* + * Are we within thread, that calls destructors of static objects ? + *******************/ +sal_Bool g_bStaticDestructorsCalled = sal_False; +struct StaticSingleton +{ + ~StaticSingleton() + { + ::osl::MutexGuard guard( ::osl::Mutex::getGlobalMutex() ); + g_bStaticDestructorsCalled = sal_True; + } +}; +StaticSingleton singleton; + +#if OSL_DEBUG_LEVEL > 1 +static MyCounter thisCounter( "Remote Environment" ); +#endif + +void SAL_CALL allThreadsAreGone( uno_Environment * pEnvRemote ) +{ + remote_Context *pContext = (remote_Context *) pEnvRemote->pContext; + urp_BridgeImpl *pImpl = ( urp_BridgeImpl *) pContext->m_pBridgeImpl; + + // if the current thread is not the writer thread, the writer thread + // object is not destroyed up to now, though it may already have run out. + // In both cases, it must be safe to cal pImpl->m_pWriter->getIdentifier() + OSL_ASSERT( pImpl->m_pWriter ); + if( pImpl->m_pWriter->getIdentifier() == osl_getThreadIdentifier(0) ) + { + // This is the writer thread. It has done some release calls, + // and is now the last one, that was active. Because the writer + // thread holds the environment weakly, there may also be a thread within + // the dispose of the bridge ( because the enviroment may have a refcount == 0 ). + // However, this thread MUST wait for the writer thread, so it is perfectly ok, + // not to set m_cndWaitForThreads. ( The check for m_nRemoteThreads is done + // after the join of the writer thread ). + } + else + { + pImpl->m_cndWaitForThreads.set(); + } + +} + +void SAL_CALL releaseStubs( uno_Environment *pEnvRemote ) +{ + + ((remote_Context * ) pEnvRemote->pContext )->m_pBridgeImpl->m_bReleaseStubsCalled = sal_True; + + remote_Interface **ppInterfaces = 0; + sal_Int32 nCount; + pEnvRemote->pExtEnv->getRegisteredInterfaces( pEnvRemote->pExtEnv, + (void***)&ppInterfaces, + &nCount, + rtl_allocateMemory ); + + sal_Int32 i; + for( i = 0 ; i < nCount ; i ++ ) + { + if( ppInterfaces[i]->acquire == bridges_remote::acquireUno2RemoteStub ) + { + // these are freed by the environment, so no release necessary + pEnvRemote->pExtEnv->revokeInterface( pEnvRemote->pExtEnv, ppInterfaces[i] ); + } + else + { + ppInterfaces[i]->release( ppInterfaces[i] ); + } + } + + rtl_freeMemory( (void*) ppInterfaces ); +} + +} // end namespace bridges_urp + +using namespace bridges_urp; + +extern "C" { + +static void SAL_CALL RemoteEnvironment_thisDispose( uno_Environment *pEnvRemote ) +{ + remote_Context *pContext = (remote_Context *) pEnvRemote->pContext; + urp_BridgeImpl *pImpl = ( urp_BridgeImpl *) pContext->m_pBridgeImpl; + + ::osl::ClearableMutexGuard guard( pImpl->m_disposingMutex ); + if( pContext->m_pBridgeImpl->m_bDisposed && + ( ! pImpl->m_pReader || + osl_getThreadIdentifier(0) == + (oslThreadIdentifier) pImpl->m_pReader->getIdentifier() ) ) + { + return; + } + // in case, that the static destructors already have been called, no + // tiding up is done. + bool tidyUp; + { + ::osl::MutexGuard guard2( ::osl::Mutex::getGlobalMutex() ); + tidyUp = ! g_bStaticDestructorsCalled && + ! pContext->m_pBridgeImpl->m_bDisposed; + } + if( tidyUp ) + { + // TODO : not threadsafe + // synchronization with dispatch methods needed ! + + pImpl->m_bDisposed = sal_True; + + + // close the connection + uno_threadpool_dispose( pImpl->m_hThreadPool ); + pImpl->m_pWriter->abortThread(); + pContext->m_pConnection->close( pContext->m_pConnection ); + + if( osl_getThreadIdentifier(0) == + (oslThreadIdentifier) pImpl->m_pReader->getIdentifier() ) + { + // This is the reader thread. Let the thread destroy itself + // the reader thread object must also release the connection at this stage ! + pImpl->m_pReader->destroyYourself(); + pImpl->m_pReader = 0; + } + else + { + // wait for the reader thread + // the reader thread object must also release the connection, + // when terminating !!!! + pImpl->m_pReader->join(); + } + + // wait for the writer thread + pImpl->m_pWriter->join(); + + // now let the context go ! + pContext->dispose( pContext ); + + if( 0 != pImpl->m_nRemoteThreads ) + { + // Wait for all threads + guard.clear(); + pImpl->m_cndWaitForThreads.wait(); + OSL_ASSERT( ! pImpl->m_nRemoteThreads ); + } + else + { + guard.clear(); + } +#ifdef BRIDGES_URP_PROT + if( pImpl->m_pLogFile ) + { + fclose( pImpl->m_pLogFile ); + pImpl->m_pLogFile = 0; + } +#endif +#if OSL_DEBUG_LEVEL > 1 + pImpl->dumpErrors( stderr ); +#endif + + // destroy the threads + delete pImpl->m_pWriter; + pImpl->m_pWriter = 0; + + if( pImpl->m_pReader != 0 ) + { + // This is not the reader thread, so the thread object is deleted + delete pImpl->m_pReader; + pImpl->m_pReader = 0; + } + + bool bReleaseStubs = false; + { + ::osl::MutexGuard guard2( ::osl::Mutex::getGlobalMutex() ); + bReleaseStubs = !g_bStaticDestructorsCalled; + } + if( bReleaseStubs ) + { + releaseStubs( pEnvRemote ); + } + } +} + +static void SAL_CALL RemoteEnvironment_thisDisposing( + uno_Environment *pEnvRemote ) +{ + remote_Context *pContext = (remote_Context * )pEnvRemote->pContext; + urp_BridgeImpl *pImpl = ((urp_BridgeImpl*) pContext->m_pBridgeImpl); + + { + ::osl::ClearableMutexGuard guard( pImpl->m_disposingMutex ); + if( ! pImpl->m_bDisposed ) + { + guard.clear(); + urp_sendCloseConnection( pEnvRemote ); + RemoteEnvironment_thisDispose( pEnvRemote ); + } + } + pImpl->m_pPropertyObject->thisRelease(); + pImpl->m_pPropertyObject = 0; + + uno_threadpool_destroy( pImpl->m_hThreadPool ); + + delete pImpl; + pContext->aBase.release( (uno_Context * ) pContext ); + g_moduleCount.modCnt.release( &g_moduleCount.modCnt ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.release(); +#endif +} + +static void SAL_CALL RemoteEnvironment_thisComputeObjectIdentifier( + uno_ExtEnvironment *, rtl_uString **, void *) +{ + OSL_ENSURE( 0, "RemoteEnvironment_thisComputeObjectIdentifier should never be called" ); +} + +static void SAL_CALL RemoteEnvironment_thisAcquireInterface( + uno_ExtEnvironment *, void *pInterface ) +{ + ((remote_Interface *)pInterface)->acquire( ( remote_Interface *) pInterface ); +} + +static void SAL_CALL RemoteEnvironment_thisReleaseInterface( + uno_ExtEnvironment *, void *pInterface ) +{ + ((remote_Interface *)pInterface)->release( ( remote_Interface *) pInterface ); +} + +//################################################################################################## +void SAL_CALL uno_initEnvironment( uno_Environment * pEnvRemote ) +{ + g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt ); + // set C-virtual methods + pEnvRemote->environmentDisposing = RemoteEnvironment_thisDisposing; + pEnvRemote->pExtEnv->computeObjectIdentifier = RemoteEnvironment_thisComputeObjectIdentifier; + pEnvRemote->pExtEnv->acquireInterface = RemoteEnvironment_thisAcquireInterface; + pEnvRemote->pExtEnv->releaseInterface = RemoteEnvironment_thisReleaseInterface; + pEnvRemote->dispose = RemoteEnvironment_thisDispose; + + remote_Context *pContext = ( remote_Context * ) pEnvRemote->pContext; + pContext->aBase.acquire( ( uno_Context * ) pContext ); + pContext->getRemoteInstance = ::bridges_remote::remote_sendQueryInterface; + + // Initialize impl struct urp_BridgeImpl + urp_BridgeImpl *pImpl = new ::bridges_urp::urp_BridgeImpl( 256, 8192 ); + pContext->m_pBridgeImpl = pImpl; + + // Initialize threadpool + pImpl->m_hThreadPool = uno_threadpool_create(); + + // take the bridgepointer as id + pImpl->m_properties.seqBridgeID = ByteSequence( (sal_Int8*)&pEnvRemote , sizeof( pEnvRemote ) ); + + pImpl->m_allThreadsAreGone = allThreadsAreGone; + pImpl->m_sendRequest = urp_sendRequest; + pImpl->m_nRemoteThreads = 0; + pImpl->m_bDisposed = sal_False; + pImpl->m_bReleaseStubsCalled = sal_False; + + pImpl->m_pPropertyObject = new PropertyObject( &(pImpl->m_properties ), pEnvRemote, pImpl ); + pImpl->m_pPropertyObject->thisAcquire(); + + OUString sProtocolProperties; + if( pContext->m_pProtocol->length > 3 ) + { + sProtocolProperties = OUString( pContext->m_pProtocol ).copy( 4, pContext->m_pProtocol->length-4); + } + if( sProtocolProperties.getLength() ) + { + struct Properties props = pImpl->m_properties; + assignFromStringToStruct( sProtocolProperties , &props ); + if( ! props.bNegotiate ) + { + // no negotiation takes place, the creator of the bridge knows the parameter + // of the other side ! + pImpl->applyProtocolChanges( props ); + sProtocolProperties = OUString(); + } + } + +#ifdef BRIDGES_URP_PROT + char *p = getenv( "PROT_REMOTE" ); + pImpl->m_pLogFile = 0; + if( p ) + { + MutexGuard guard( Mutex::getGlobalMutex() ); + static int counter; + oslProcessInfo data; + data.Size = sizeof( data ); + osl_getProcessInfo( 0 , osl_Process_HEAPUSAGE | osl_Process_IDENTIFIER , &data ); + OString s(p); + s += "_pid"; + s += OString::valueOf( (sal_Int32) data.Ident ); + s += "_"; + s += OString::valueOf( (sal_Int32) counter ); + pImpl->m_sLogFileName = s; + // clear the file + FILE *f = fopen( s.getStr() , "w" ); + OSL_ASSERT( f ); + if( getenv( "PROT_REMOTE_FAST") ) + { + pImpl->m_pLogFile = f; + } + else + { + fclose( f ); + } + counter++; + } +#endif + + // start reader and writer threads + pImpl->m_pWriter = new ::bridges_urp::OWriterThread( pContext->m_pConnection , pImpl, + pEnvRemote); + pImpl->m_pWriter->create(); + + pImpl->m_pReader = new ::bridges_urp::OReaderThread( pContext->m_pConnection , + pEnvRemote, + pImpl->m_pWriter ); + pImpl->m_pReader->create(); + + PropertySetterThread *pPropsSetterThread = + new PropertySetterThread( pEnvRemote, pImpl , sProtocolProperties ); + pPropsSetterThread->create(); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.acquire(); +#endif +} + + +//################################################################################################## +void SAL_CALL uno_ext_getMapping( + uno_Mapping ** ppMapping, + uno_Environment * pFrom, + uno_Environment * pTo ) +{ + OSL_ASSERT( ppMapping && pFrom && pTo ); + if (ppMapping && pFrom && pTo) + { + if (*ppMapping) + ((*ppMapping)->release)( *ppMapping ); + bridges_remote::RemoteMapping * pMapping = 0; + + ::rtl::OUString sFromName = pFrom->pTypeName; + ::rtl::OUString sToName = pTo->pTypeName; + ::rtl::OUString sUno = OUString::createFromAscii( UNO_LB_UNO ); + ::rtl::OUString sRemote = OUString::createFromAscii( "urp" ); + if ( sFromName.equalsIgnoreAsciiCase( sRemote ) && + sToName.equalsIgnoreAsciiCase( sUno ) ) + { + pMapping = new bridges_remote::RemoteMapping( pTo, /* Uno */ + pFrom, /*remote*/ + bridges_remote::remoteToUno, + OUString() ); + } + else if ( sFromName.equalsIgnoreAsciiCase( sUno ) && + sToName.equalsIgnoreAsciiCase( sRemote ) ) + { + pMapping = new bridges_remote::RemoteMapping( pFrom , + pTo , + bridges_remote::unoToRemote, + OUString() ); + } + + *ppMapping = (uno_Mapping * )pMapping; + OUString dummy; + uno_registerMapping( ppMapping , + bridges_remote::freeRemoteMapping, + pFrom , + pTo , + dummy.pData ); + } +} + +sal_Bool SAL_CALL component_canUnload( TimeValue *pTime ) +{ + return g_moduleCount.canUnload( &g_moduleCount , pTime ); +} + +} diff --git a/bridges/source/remote/urp/urp_job.cxx b/bridges/source/remote/urp/urp_job.cxx new file mode 100644 index 000000000000..8828f7f37f64 --- /dev/null +++ b/bridges/source/remote/urp/urp_job.cxx @@ -0,0 +1,939 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <string.h> +#include <stdio.h> +#include <osl/diagnose.h> +#include <osl/mutex.hxx> + +#include <rtl/alloc.h> +#include <rtl/ustrbuf.hxx> + +#include <uno/current_context.h> +#include <uno/current_context.hxx> +#include <uno/threadpool.h> + +#include <bridges/cpp_uno/type_misc.hxx> +#include <bridges/remote/proxy.hxx> + +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/XCurrentContext.hpp> +#include <com/sun/star/lang/DisposedException.hpp> + +#include "urp_job.hxx" +#include "urp_bridgeimpl.hxx" +#include "urp_writer.hxx" +#include "urp_dispatch.hxx" +#include "urp_log.hxx" +#include "urp_marshal.hxx" +#include "urp_propertyobject.hxx" +#include "urp_reader.hxx" + +using namespace ::std; +using namespace ::rtl; +using namespace ::osl; +using namespace ::com::sun::star::uno; + +using namespace bridges_urp; + +extern "C" { + +static void SAL_CALL doit(void * job) { + ServerMultiJob * p = static_cast< ServerMultiJob * >(job); + p->execute(); + delete p; +} + +} + +namespace bridges_urp +{ + static sal_Bool isDisposedExceptionDescriptionAvail( const Type &type ) + { + static sal_Bool bInit; + static sal_Bool bReturn; + // we don't care for thread safety here, as both threads must come + // to the same result + if( ! bInit ) + { + typelib_TypeDescription *pTD = 0; + typelib_typedescriptionreference_getDescription( & pTD, type.getTypeLibType() ); + if( pTD ) + { + bReturn = sal_True; + typelib_typedescription_release( pTD ); + } + else + { + bReturn = sal_False; + } + bInit = sal_True; + } + return bReturn; + } + + //-------------------------------------------------------------------------------------- + static void prepareRuntimeExceptionClientSide( uno_Any **ppException , const OUString &s) + { + com::sun::star::lang::DisposedException exception( s , Reference< XInterface > () ); + Type type = ::getCppuType( &exception ); + if( !isDisposedExceptionDescriptionAvail( type ) ) + { + // if it is not available (probably missing type library), + // then we are satisfied with throwing a normal runtime exception, + // for which cppu provides a static description + type = getCppuType( ( RuntimeException * ) 0 ); + } + uno_type_any_construct( *ppException , &exception , type.getTypeLibType() , 0 ); + } + + + Job::Job( uno_Environment *pEnvRemote, + remote_Context *pContext, + sal_Sequence *pTid, + struct urp_BridgeImpl *pBridgeImpl, + Unmarshal *pUnmarshal ) + : m_pContext( pContext ) + , m_pUnmarshal( pUnmarshal ) + , m_pBridgeImpl( pBridgeImpl ) + , m_pTid( pTid ) + , m_counter( pEnvRemote ) + { + if ( m_pContext ) + { + m_pContext->aBase.acquire( &m_pContext->aBase ); + } + if( m_pTid ) + rtl_byte_sequence_acquire( pTid ); + } + + Job::~Job() + { + if( m_pTid ) + rtl_byte_sequence_release( m_pTid ); + if ( m_pContext ) + { + m_pContext->aBase.release( &m_pContext->aBase ); + } + } + + + + + //-------------------------------------------------------------------------------------- + sal_Bool ClientJob::extract( ) + { + sal_Bool bReturn = sal_True; + //------------------------------- + // Handle the reply, unpack data + //------------------------------- + if( m_bExceptionOccured ) + { + bReturn = m_pUnmarshal->unpackAny( *m_ppException ); + } + else + { + //--------------------------------- + // alles ist gut + //--------------------------------- + if( m_pMethodType ) + { + if( m_pMethodType->pReturnTypeRef->eTypeClass != typelib_TypeClass_VOID ) + { + typelib_TypeDescription *pType = 0; + TYPELIB_DANGER_GET( &pType , m_pMethodType->pReturnTypeRef ); + bReturn = m_pUnmarshal->unpack( m_pReturn , pType ) && bReturn; + TYPELIB_DANGER_RELEASE( pType ); + } + + // out parameters + sal_Int32 i; + for( i = 0 ; i < m_pMethodType->nParams ; i ++ ) + { + if( m_pMethodType->pParams[i].bOut ) + { + typelib_TypeDescription *pType = 0; + TYPELIB_DANGER_GET( &pType , m_pMethodType->pParams[i].pTypeRef ); + if( m_pMethodType->pParams[i].bIn ) + { + uno_destructData( m_ppArgs[i] , pType , ::bridges_remote::remote_release ); + } + bReturn = m_pUnmarshal->unpack( m_ppArgs[i] , pType ) && bReturn; + TYPELIB_DANGER_RELEASE( pType ); + } + } + } + else if( m_pAttributeType && m_pReturn ) + { + typelib_TypeDescription *pType = 0; + TYPELIB_DANGER_GET( &pType , m_pAttributeType->pAttributeTypeRef ); + bReturn = m_pUnmarshal->unpack( m_pReturn , pType ) && bReturn; + TYPELIB_DANGER_RELEASE( pType ); + } + else if( m_pAttributeType && m_ppArgs ) + { + // nothing to do + } + else + { + OSL_ASSERT( 0 ); + } + } + return bReturn; + } + + //------------------------------------------------------------------------------------------- + void ClientJob::initiate() + { + uno_threadpool_putJob( m_pBridgeImpl->m_hThreadPool, m_pTid , this, 0, sal_False); + } + + //-------------------------------------------------------------------------------------------- + sal_Bool ClientJob::pack() + { + sal_Bool bSuccess = sal_True; + MutexGuard guard( m_pBridgeImpl->m_marshalingMutex ); + + if( m_pMethodType && + REMOTE_RELEASE_METHOD_INDEX == m_pMethodType->aBase.nPosition && + ! m_pBridgeImpl->m_bDisposed && + m_pBridgeImpl->m_pWriter->getIdentifier() != ::osl::Thread::getCurrentIdentifier() ) + { + // all release calls are delegated to the writer thread to avoid + // multiple synchron calls with the same thread id and reentrant + // marshaling (in case during destruction of parameters a release is + // invoked ). + m_pBridgeImpl->m_pWriter->insertReleaseRemoteCall( + m_pOid, m_pInterfaceType->aBase.pWeakRef ); + + // No waiting, please + return sal_False; + } + else if ( m_pMethodType && + REMOTE_RELEASE_METHOD_INDEX == m_pMethodType->aBase.nPosition && + m_pBridgeImpl->m_bDisposed ) + { + // no exception for release calls ! + return sal_False; + } + else if( m_pBridgeImpl->m_bDisposed ) + { + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "URP-Bridge: disposed" ) ); + buf.append( m_pBridgeImpl->getErrorsAsString() ); + prepareRuntimeExceptionClientSide( m_ppException , buf.makeStringAndClear() ); + return sal_False; + } + + // build up the flag byte + sal_Bool bType = sal_False, bOid = sal_False, bTid = sal_False; + sal_uInt8 nFlags = 0; + if( m_pBridgeImpl->m_lastOutType.getTypeLibType() != m_pInterfaceType->aBase.pWeakRef && + ! typelib_typedescriptionreference_equals( + m_pBridgeImpl->m_lastOutType.getTypeLibType(), m_pInterfaceType->aBase.pWeakRef ) ) + { + //new type + nFlags = nFlags | HDRFLAG_NEWTYPE; + bType = sal_True; + } + if( m_pBridgeImpl->m_lastOutOid.pData != m_pOid && + rtl_ustr_compare_WithLength( m_pBridgeImpl->m_lastOutOid.pData->buffer, + m_pBridgeImpl->m_lastOutOid.pData->length, + m_pOid->buffer, + m_pOid->length ) ) + { + //new object id + nFlags = nFlags | HDRFLAG_NEWOID; + bOid = sal_True; + } + if( m_pBridgeImpl->m_lastOutTid.getHandle() != m_pTid && + !(m_pBridgeImpl->m_lastOutTid == *(ByteSequence*) &(m_pTid) ) ) + { + // new threadid + nFlags = nFlags | HDRFLAG_NEWTID; + bTid = sal_True; + } + + if( m_bCallingConventionForced ) + { + nFlags = nFlags | HDRFLAG_MOREFLAGS; + } +#ifdef BRIDGES_URP_PROT + sal_Int32 nLogStart = m_pBridgeImpl->m_blockMarshaler.getPos(); +#endif + // Short request headers can only handle 14-bit method IDs, so + // unconditionally use a long header for method IDs that are too large: + if( nFlags || m_nMethodIndex >= 0xC000 ) + { + // the flag byte is needed + request + nFlags = nFlags | HDRFLAG_LONGHEADER | HDRFLAG_REQUEST; // + + // as long as we do not have customized calls, no MOREFLAGS must be set + if( m_nMethodIndex >= 0x100 ) + { + nFlags = nFlags | HDRFLAG_LONGMETHODID; + } + m_pBridgeImpl->m_blockMarshaler.packInt8( &nFlags ); + + if( nFlags & HDRFLAG_MOREFLAGS ) + { + sal_uInt8 nMoreFlags = 0; + if( ! m_bOneway ) + { + nMoreFlags = HDRFLAG_SYNCHRONOUS |HDRFLAG_MUSTREPLY; + } + m_pBridgeImpl->m_blockMarshaler.packInt8( &nMoreFlags ); + } + if( nFlags & HDRFLAG_LONGMETHODID ) + { + sal_uInt16 nMethod = (sal_uInt16 ) m_nMethodIndex; + m_pBridgeImpl->m_blockMarshaler.packInt16( &nMethod ); + } + else + { + sal_uInt8 nMethod = (sal_uInt8) m_nMethodIndex; + m_pBridgeImpl->m_blockMarshaler.packInt8( &nMethod ); + } + } + else + { + // no flag byte needed, simply marshal the method index + if( m_nMethodIndex >= 64 ) + { + sal_uInt16 nMethod = ( sal_uInt16 ) m_nMethodIndex; + nMethod = nMethod | 0x4000; + m_pBridgeImpl->m_blockMarshaler.packInt16( &nMethod ); + } + else + { + sal_uInt8 nMethod = (sal_uInt8 ) m_nMethodIndex; + m_pBridgeImpl->m_blockMarshaler.packInt8( &nMethod ); + } + } + + // marshal type,oid,tid + if( bType ) + { + m_pBridgeImpl->m_lastOutType = m_pInterfaceType->aBase.pWeakRef; + m_pBridgeImpl->m_blockMarshaler.packType( &(m_pBridgeImpl->m_lastOutType) ); + } + if( bOid ) + { + m_pBridgeImpl->m_lastOutOid = *(OUString *)&m_pOid; + m_pBridgeImpl->m_blockMarshaler.packOid( m_pBridgeImpl->m_lastOutOid ); + } + if( bTid ) + { + m_pBridgeImpl->m_lastOutTid = *(ByteSequence*)&(m_pTid); + m_pBridgeImpl->m_blockMarshaler.packTid( m_pBridgeImpl->m_lastOutTid ); + } + + if ( m_pBridgeImpl->m_properties.bCurrentContext + && m_nMethodIndex != REMOTE_RELEASE_METHOD_INDEX + && m_pContext != 0 ) + { + void * pCc = 0; + rtl::OUString aEnvName( RTL_CONSTASCII_USTRINGPARAM( "urp" ) ); + bSuccess = bSuccess && uno_getCurrentContext( + &pCc, aEnvName.pData, m_pContext ); + typelib_TypeDescription * pType = 0; + TYPELIB_DANGER_GET( + &pType, XCurrentContext::static_type().getTypeLibType() ); + bSuccess = bSuccess && m_pBridgeImpl->m_blockMarshaler.pack( + &pCc, pType ); + TYPELIB_DANGER_RELEASE( pType ); + if ( pCc ) + { + remote_Interface * p = static_cast< remote_Interface * >( pCc ); + p->release( p ); + } + } + + // marshal arguments ! +#ifdef BRIDGES_URP_PROT + sal_Int32 nLogHeader = m_pBridgeImpl->m_blockMarshaler.getPos(); +#endif + if( m_pMethodType ) + { + sal_Int32 i; + for( i = 0 ; i < m_pMethodType->nParams ; i ++ ) + { + if( m_pMethodType->pParams[i].bIn ) + { + typelib_TypeDescription *pType = 0; + TYPELIB_DANGER_GET( &pType , m_pMethodType->pParams[i].pTypeRef ); + if( pType ) + { + bSuccess = + bSuccess && m_pBridgeImpl->m_blockMarshaler.pack( m_ppArgs[i] , pType ); + TYPELIB_DANGER_RELEASE( pType ); + } + else + { + bSuccess = sal_False; + OUStringBuffer buffer( 128 ); + buffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "no typedescription available for type" ) ); + buffer.append( m_pMethodType->pParams[i].pTypeRef->pTypeName ); + m_pBridgeImpl->addError( buffer.makeStringAndClear() ); + } + } + } + } + else if( m_pAttributeType && m_pReturn ) + { + // nothing to do ! + } + else if( m_pAttributeType && m_ppArgs ) + { + typelib_TypeDescription *pType = 0; + TYPELIB_DANGER_GET( &pType , m_pAttributeType->pAttributeTypeRef ); + if( pType ) + { + bSuccess = bSuccess && m_pBridgeImpl->m_blockMarshaler.pack( m_ppArgs[0] , pType ); + TYPELIB_DANGER_RELEASE( pType ); + } + else + { + bSuccess = sal_False; + OUStringBuffer buffer( 128 ); + buffer.appendAscii( RTL_CONSTASCII_STRINGPARAM( "no typedescription available for type" ) ); + buffer.append( m_pAttributeType->pAttributeTypeRef->pTypeName ); + m_pBridgeImpl->addError( buffer.makeStringAndClear() ); + } + } + else + { + OSL_ASSERT( 0 ); + } + +#ifdef BRIDGES_URP_PROT + urp_logCall( m_pBridgeImpl, m_pBridgeImpl->m_blockMarshaler.getPos() - nLogStart, + m_pBridgeImpl->m_blockMarshaler.getPos() - nLogHeader, ! m_bOneway, + m_pMethodType ? m_pMethodType->aBase.pMemberName : + m_pAttributeType->aBase.pMemberName ); +#endif + + if( bSuccess ) + { + if( ! m_bOneway ) + { + uno_threadpool_attach( m_pBridgeImpl->m_hThreadPool ); + m_pBridgeImpl->m_clientJobContainer.add( *(ByteSequence*)&(m_pTid), this ); + } + + m_pBridgeImpl->m_nMarshaledMessages ++; + //--------------------------- + // Inform the writer thread, that there is some work to do + //--------------------------- + m_pBridgeImpl->m_pWriter->touch( ! m_bOneway ); + + if( m_bOneway ) + { + *m_ppException = 0; + } + } + else + { + // Something went wrong during packing, which means, that the caches may not be in sync + // anymore. So we have no other choice than to dispose the environment. + m_pEnvRemote->dispose( m_pEnvRemote ); + OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "Error during marshaling " ) ); + if( m_pMethodType ) + { + buf.append( m_pMethodType->aBase.aBase.pTypeName ); + } + else if( m_pAttributeType ) + { + buf.append( m_pAttributeType->aBase.aBase.pTypeName ); + } + buf.appendAscii( "\n" ); + buf.append( m_pBridgeImpl->getErrorsAsString() ); + prepareRuntimeExceptionClientSide( m_ppException , buf.makeStringAndClear() ); + } + return bSuccess; + // release the guard + } + + //------------------------------------------------------------------------------------ + void ClientJob::wait() + { + //--------------------------- + // Wait for the reply + //--------------------------- + void * pDisposeReason = 0; + + uno_threadpool_enter(m_pBridgeImpl->m_hThreadPool, &pDisposeReason ); + + if( ! pDisposeReason ) + { + // thread has been disposed ! + // avoid leak due continous calling on a disposed reference. The + // reply may or may not be within the container. If the reader thread + // got into problems during unmarshaling the reply for this request, + // it won't be in the container anymore, but it is eiterway safe to call + // the method + ClientJob *pJob = + m_pBridgeImpl->m_clientJobContainer.remove( *(ByteSequence*) &m_pTid ); + if( pJob != this ) + { + // this is not our job, it is probably one of the callstack below, so + // push it back + m_pBridgeImpl->m_clientJobContainer.add( *(ByteSequence*) &m_pTid , pJob ); + } + + OUStringBuffer sMessage( 256 ); + sMessage.appendAscii( RTL_CONSTASCII_STRINGPARAM( "URP_Bridge : disposed\n" ) ); + sMessage.append( m_pBridgeImpl->getErrorsAsString() ); + prepareRuntimeExceptionClientSide( m_ppException, sMessage.makeStringAndClear() ); + m_bExceptionOccured = sal_True; + } + else + { + OSL_ASSERT( pDisposeReason == (void*)this ); + } + if( !m_bExceptionOccured ) + { + *m_ppException = 0; + } + uno_threadpool_detach( m_pBridgeImpl->m_hThreadPool ); + } + + //------------------------------------------------------------------------------------ + // ServerMultiJob + //------------------------------------------------------------------------------------ + ServerMultiJob::ServerMultiJob( + uno_Environment *pEnvRemote, + remote_Context *pContext, + sal_Sequence *pTid, + struct urp_BridgeImpl *pBridgeImpl, + Unmarshal *pUnmarshal, + sal_Int32 nMaxMessages ) + : Job( pEnvRemote, pContext, pTid, pBridgeImpl, pUnmarshal ) + , m_pEnvRemote( pEnvRemote ) + , m_nCalls( 0 ) + , m_nMaxMessages( nMaxMessages ) + , m_nCurrentMemPosition( 0 ) + { + m_pEnvRemote->acquire( m_pEnvRemote ); + m_nCurrentMemSize = MULTIJOB_STANDARD_MEMORY_SIZE + m_nMaxMessages * ( + MULTIJOB_PER_CALL_MEMORY_SIZE + sizeof(ServerJobEntry) + sizeof(MemberTypeInfo) ); + m_pCurrentMem = ( sal_Int8 * ) rtl_allocateMemory( m_nCurrentMemSize ); + m_aEntries = ( ServerJobEntry * ) getHeap( m_nMaxMessages * sizeof( ServerJobEntry ) ); + m_aTypeInfo = ( MemberTypeInfo * ) getHeap( m_nMaxMessages * sizeof( MemberTypeInfo ) ); + } + + ServerMultiJob::~ServerMultiJob() + { + sal_Int32 i; + for( i = 0 ; i < m_nCalls ; i ++ ) + { + struct MemberTypeInfo *const pMTI = &( m_aTypeInfo[i] ); + struct ServerJobEntry *const pSJE = &( m_aEntries[i] ); + + if( pSJE->m_pRemoteI ) + pSJE->m_pRemoteI->release( pSJE->m_pRemoteI ); + + if( pSJE->m_pOid ) + rtl_uString_release( pSJE->m_pOid ); + + if( pSJE->m_pInterfaceTypeRef ) + typelib_typedescriptionreference_release( pSJE->m_pInterfaceTypeRef ); + + if( pMTI->m_pInterfaceType ) + TYPELIB_DANGER_RELEASE( (typelib_TypeDescription *)pMTI->m_pInterfaceType ); + + for( sal_Int32 iArgs = 0 ; iArgs < pMTI->m_nArgCount ; iArgs ++ ) + { + if( pMTI->m_ppArgType[iArgs] ) + TYPELIB_DANGER_RELEASE( pMTI->m_ppArgType [iArgs] ); + } + if( pMTI->m_pReturnType ) + TYPELIB_DANGER_RELEASE( pMTI->m_pReturnType ); + + if( pMTI->m_pMethodType ) + typelib_typedescription_release( (typelib_TypeDescription*)pMTI->m_pMethodType ); + if( pMTI->m_pAttributeType ) + typelib_typedescription_release( (typelib_TypeDescription*)pMTI->m_pAttributeType ); + } + + rtl_freeMemory( m_pCurrentMem ); + for( list< sal_Int8 *>::iterator ii = m_lstMem.begin() ; ii != m_lstMem.end() ; ++ii ) + rtl_freeMemory( *ii ); + + if( m_pEnvRemote ) + m_pEnvRemote->release( m_pEnvRemote ); + } + + //------------------------------------------------------------------------------------- + void ServerMultiJob::execute() + { + Reference< XCurrentContext > xOldCc; + bool bHasOldCc = false; + for( sal_Int32 i = 0; i < m_nCalls ; i ++ ) + { + struct MemberTypeInfo * const pMTI = &( m_aTypeInfo[i] ); + struct ServerJobEntry * const pSJE = &( m_aEntries[i] ); + + if ( pSJE->m_bHasCurrentContext ) + { + if ( !bHasOldCc ) + { + xOldCc = com::sun::star::uno::getCurrentContext(); + bHasOldCc = true; + } + rtl::OUString aEnvName( RTL_CONSTASCII_USTRINGPARAM( "urp" ) ); + if ( !uno_setCurrentContext( + pSJE->m_pCurrentContext, aEnvName.pData, m_pContext ) ) + { + throw RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "fatal: uno_setCurrentContext failed" ) ), + Reference< XInterface >() ); + } + if ( pSJE->m_pCurrentContext ) + { + pSJE->m_pCurrentContext->release( pSJE->m_pCurrentContext ); + } + } + + if( ! pSJE->m_pRemoteI ) + { + // ------------------- + // Initial object ? + // ------------------ + // be robust : Sending a release on a not constructed object + // provokes an segfault. Make sure, the call + // is not a release call. + remote_Context *pRemoteC = ((remote_Context*)m_pEnvRemote->pContext); + + if( ! pMTI->m_bIsReleaseCall && pRemoteC->m_pInstanceProvider ) + { + pSJE->m_pException = &(pSJE->m_exception); + + pRemoteC->m_pInstanceProvider->getInstance( + pRemoteC->m_pInstanceProvider, + m_pEnvRemote, + &(pSJE->m_pRemoteI), + pSJE->m_pOid, + pMTI->m_pInterfaceType, + &(pSJE->m_pException)); + } + else + { + prepareRuntimeException( + OUString( RTL_CONSTASCII_USTRINGPARAM( "urp: No instance provider set")),i); + } + } + + if( pSJE->m_pException ) + { + // errors during extracting, do nothing + } + else if( ! pSJE->m_pRemoteI ) + { + // May only occur during the queryInterface call on the initial object !!! + // construct the return value + uno_type_any_construct( (uno_Any*) pSJE->m_pReturn , 0 , 0 , 0 ); + } + else + { + pSJE->m_pException = &(pSJE->m_exception ); + + if( pMTI->m_bIsReleaseCall ) + { + pSJE->m_pRemoteI->release( pSJE->m_pRemoteI ); + pSJE->m_pException = 0; + } + else + { + pSJE->m_pRemoteI->pDispatcher( + pSJE->m_pRemoteI, + pMTI->m_pMethodType ? (typelib_TypeDescription*) pMTI->m_pMethodType : + (typelib_TypeDescription*) pMTI->m_pAttributeType, + pSJE->m_pReturn, + pSJE->m_ppArgs, + &(pSJE->m_pException) ); + } + } + if( pSJE->m_pRemoteI ) + { + /** + Do the release here, in case of ForceSynchronous=1, calls + originated by the destructor of an UNO object must be sent BEFORE the + release returns ( otherwise we don't own the thread anymore ! ) + */ + pSJE->m_pRemoteI->release( pSJE->m_pRemoteI ); + pSJE->m_pRemoteI = 0; + } + + // now destruct parameters and marshal replies + // Note : when call is synchron => m_nCalls == 1 + if( pMTI->m_bIsOneway ) + { + // Oneway call, destruct in parameters + for( sal_Int32 j = 0 ; j < pMTI->m_pMethodType->nParams ; j ++ ) + { + // usually all parameters must be in parameters, but to be robust ... + if( pMTI->m_pbIsIn[j] && !cppu_isSimpleType( pMTI->m_ppArgType[j] ) ) + { + uno_destructData( pSJE->m_ppArgs[j] , pMTI->m_ppArgType[j] , 0 ); + } + } + + if( pSJE->m_pException ) + { + uno_any_destruct( pSJE->m_pException, ::bridges_remote::remote_release ); + } + + } + else + { + // synchron, get the mutex to marshal reply and send immeadiatly + MutexGuard guard( m_pBridgeImpl->m_marshalingMutex ); + + sal_Bool bTid = sal_False; + sal_uInt8 nFlags = HDRFLAG_LONGHEADER; + ByteSequence tid = m_pTid; + if( !( tid == m_pBridgeImpl->m_lastOutTid ) || pSJE->m_bIgnoreCache ) + { + // new threadid + nFlags = nFlags | HDRFLAG_NEWTID; + bTid = sal_True; + } + + if( pSJE->m_pException ) + { + nFlags = nFlags | HDRFLAG_EXCEPTION; + } +#ifdef BRIDGES_URP_PROT + sal_Int32 nLogStart = m_pBridgeImpl->m_blockMarshaler.getPos(); +#endif + m_pBridgeImpl->m_blockMarshaler.packInt8( &nFlags ); + + if( bTid ) + { + if( ! pSJE->m_bIgnoreCache ) + { + m_pBridgeImpl->m_lastOutTid = tid; + } + m_pBridgeImpl->m_blockMarshaler.packTid( tid , pSJE->m_bIgnoreCache ); + } + +#ifdef BRIDGES_URP_PROT + sal_Int32 nLogHeader = m_pBridgeImpl->m_blockMarshaler.getPos(); +#endif + + if( pSJE->m_pException ) + { + //-------------------- + // an exception was thrown + //-------------------- + m_pBridgeImpl->m_blockMarshaler.packAny( &(pSJE->m_exception) ); + uno_any_destruct( &(pSJE->m_exception) , ::bridges_remote::remote_release ); + + // destroy in parameters + for( sal_Int32 j = 0 ; j < pMTI->m_nArgCount ; j ++ ) + { + if( pMTI->m_pbIsIn[j] && ! cppu_isSimpleType( pMTI->m_ppArgType[j] )) + { + uno_destructData( pSJE->m_ppArgs[j] , pMTI->m_ppArgType[j] , + ::bridges_remote::remote_release ); + } + } + } + else + { + //--------------------------- + // alles ist gut ... + //-------------------------- + if( pMTI->m_pReturnType ) + { + m_pBridgeImpl->m_blockMarshaler.pack( + pSJE->m_pReturn, pMTI->m_pReturnType ); + if( ! cppu_isSimpleType( pMTI->m_pReturnType ) ) + { + uno_destructData( pSJE->m_pReturn , pMTI->m_pReturnType , + ::bridges_remote::remote_release ); + } + } + for( sal_Int32 j = 0 ; j < pMTI->m_nArgCount ; j ++ ) + { + if( pMTI->m_pbIsOut[j] ) + { + m_pBridgeImpl->m_blockMarshaler.pack( + pSJE->m_ppArgs[j] , pMTI->m_ppArgType[j] ); + } + if( ! cppu_isSimpleType( pMTI->m_ppArgType[j] ) ) + { + uno_destructData( pSJE->m_ppArgs[j], pMTI->m_ppArgType[j] , + ::bridges_remote::remote_release ); + } + } + } + +#ifdef BRIDGES_URP_PROT + { + typelib_InterfaceMemberTypeDescription *pMemberType = + pMTI->m_pMethodType ? + (typelib_InterfaceMemberTypeDescription*)pMTI->m_pMethodType : + (typelib_InterfaceMemberTypeDescription*)pMTI->m_pAttributeType; + + urp_logReplying( m_pBridgeImpl , + m_pBridgeImpl->m_blockMarshaler.getPos() - nLogStart, + m_pBridgeImpl->m_blockMarshaler.getPos() - nLogHeader, + pMemberType->pMemberName ); + } +#endif + + m_pBridgeImpl->m_nMarshaledMessages ++; + // put it on the wire + m_pBridgeImpl->m_pWriter->touch( sal_True ); + } // MutexGuard marshalingMutex + } + if ( bHasOldCc ) + { + if ( !com::sun::star::uno::setCurrentContext( xOldCc ) ) + { + throw RuntimeException( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "fatal: com::sun::star::uno::setCurrentContext" + " failed" ) ), + Reference< XInterface >() ); + } + } + } + + //------------------------------------------------------------------------------------- + void ServerMultiJob::prepareRuntimeException( const OUString & sMessage , sal_Int32 nCall ) + { + // ------------------------------- + // Construct the DisposedException + // ------------------------------- + com::sun::star::lang::DisposedException exception( sMessage , Reference< XInterface > () ); + Type type = getCppuType( &exception ); + if( !isDisposedExceptionDescriptionAvail( type ) ) + { + // if it is not available (probably missing type library), + // then we are satisfied with throwing a normal runtime exception, + // for which cppu provides a static description + type = getCppuType( ( RuntimeException * ) 0 ); + } + + m_aEntries[nCall].m_pException = &(m_aEntries[nCall].m_exception); + uno_type_any_construct( m_aEntries[nCall].m_pException , &exception , type.getTypeLibType() , 0 ); + } + + //------------------------------------------------------------------------------------- + void ServerMultiJob::initiate() + { + uno_threadpool_putJob( + m_pBridgeImpl->m_hThreadPool, + m_pTid, + this, + doit, + m_aTypeInfo[0].m_bIsOneway ); + } + + + //------------------------------------------------------------------------------------- + sal_Bool ServerMultiJob::extract() + { + sal_Bool bContinue = sal_True; + struct MemberTypeInfo * const pMTI = &(m_aTypeInfo[m_nCalls]); + struct ServerJobEntry * const pSJE = &(m_aEntries[m_nCalls]); + + pSJE->m_pException = 0; + pSJE->m_ppArgs = 0; + pSJE->m_pReturn = 0; + pMTI->m_pReturnType = 0; + + if( pMTI->m_nArgCount ) + { + pMTI->m_ppArgType = + ( typelib_TypeDescription ** ) getHeap( sizeof(void*) * pMTI->m_nArgCount ); + pSJE->m_ppArgs = (void**) getHeap( sizeof( void * ) * pMTI->m_nArgCount ); + pMTI->m_pbIsIn = (sal_Bool *) getHeap( sizeof( sal_Bool ) * pMTI->m_nArgCount ); + pMTI->m_pbIsOut = (sal_Bool *) getHeap( sizeof( sal_Bool ) * pMTI->m_nArgCount ); + } + if( pMTI->m_pMethodType && + pMTI->m_pMethodType->pReturnTypeRef->eTypeClass != typelib_TypeClass_VOID ) + { + TYPELIB_DANGER_GET( &(pMTI->m_pReturnType), pMTI->m_pMethodType->pReturnTypeRef ); + } + else if( pMTI->m_pAttributeType && ! pMTI->m_nArgCount ) + { + TYPELIB_DANGER_GET( &(pMTI->m_pReturnType) , pMTI->m_pAttributeType->pAttributeTypeRef ); + } + + // normal method + if( pMTI->m_pMethodType ) + { + for( sal_Int32 i = 0 ; i < pMTI->m_nArgCount ; i ++ ) + { + pMTI->m_ppArgType[i] = 0; + TYPELIB_DANGER_GET( & ( pMTI->m_ppArgType[i] ) , pMTI->m_pMethodType->pParams[i].pTypeRef); + pMTI->m_pbIsIn[i] = pMTI->m_pMethodType->pParams[i].bIn; + pMTI->m_pbIsOut[i] = pMTI->m_pMethodType->pParams[i].bOut; + + pSJE->m_ppArgs[i] = getHeap( pMTI->m_ppArgType[i]->nSize ); + if( pMTI->m_pbIsIn[i] ) + { + // everything needs to be constructed + bContinue = m_pUnmarshal->unpack( + pSJE->m_ppArgs[i], pMTI->m_ppArgType[i] ) && bContinue; + } + } + } + else if( pMTI->m_nArgCount ) + { + // set attribut + pMTI->m_ppArgType[0] = 0; + pMTI->m_pbIsIn[0] = sal_True; + pMTI->m_pbIsOut[0] = sal_False; + TYPELIB_DANGER_GET( + & ( pMTI->m_ppArgType[0] ) , pMTI->m_pAttributeType->pAttributeTypeRef ); + pSJE->m_ppArgs[0] = getHeap( pMTI->m_ppArgType[0]->nSize ); + bContinue = m_pUnmarshal->unpack( + pSJE->m_ppArgs[0], pMTI->m_ppArgType[0] ) && bContinue; + } + + if( pMTI->m_pReturnType ) + { + pSJE->m_pReturn = getHeap( pMTI->m_pReturnType->nSize ); + } + + m_nCalls ++; + return bContinue; + } +} + + diff --git a/bridges/source/remote/urp/urp_job.hxx b/bridges/source/remote/urp/urp_job.hxx new file mode 100644 index 000000000000..ce58b1f3f779 --- /dev/null +++ b/bridges/source/remote/urp/urp_job.hxx @@ -0,0 +1,378 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _URP_JOB_HXX_ +#define _URP_JOB_HXX_ +#include <list> +#include <typelib/typedescription.hxx> +#include <uno/any2.h> +#include <uno/environment.h> +#include <uno/threadpool.h> +#include "urp_threadid.hxx" +#include "urp_unmarshal.hxx" +#include "urp_bridgeimpl.hxx" + + +namespace bridges_urp +{ +const sal_Int32 MULTIJOB_STANDARD_MEMORY_SIZE = 1024; +const sal_Int32 MULTIJOB_PER_CALL_MEMORY_SIZE = 96; + +class Unmarshal; +struct urp_BridgeImpl; + +template < class t > +inline t mymax( const t &t1 , const t &t2 ) +{ + return t1 > t2 ? t1 : t2; +} + +class Job +{ +public: + Job( uno_Environment *pEnvRemote, + remote_Context *pContext, + sal_Sequence *pTid, + struct urp_BridgeImpl *pBridgeImpl, + Unmarshal *pUnmarshal ); + + Job( uno_Environment *pEnvRemote, + remote_Context *pContext, + struct urp_BridgeImpl *pBridgeImpl, + ::bridges_remote::RemoteThreadCounter_HoldEnvWeak value ) + : m_pContext( pContext ) + , m_pBridgeImpl( pBridgeImpl ) + , m_pTid( 0 ) + , m_counter( pEnvRemote , value ) + { + if ( m_pContext ) + { + m_pContext->aBase.acquire( &m_pContext->aBase ); + } + } + + ~Job(); + +public: + remote_Context *m_pContext; + Unmarshal *m_pUnmarshal; + struct urp_BridgeImpl *m_pBridgeImpl; + sal_Sequence *m_pTid; + ::bridges_remote::RemoteThreadCounter m_counter; +}; + +class ClientJob : private Job +{ +public: + // pContext is null for bridge-internal UrpProtocolProperties requests + inline ClientJob( uno_Environment *pEnvRemote, // weak ! + remote_Context *pContext, + struct urp_BridgeImpl *pBridgeImpl, + rtl_uString *pOid, // weak + typelib_TypeDescription const * pMemberType, // weak + typelib_InterfaceTypeDescription *pInterfaceType, // weak + void *pReturn, + void *ppArgs[], + uno_Any **ppException ); + + // ~ClientJob + // no release for method type and attribute type necessary, because + // it was acquired by the caller of urp_sendRequest. The lifetime + // of the ClientJob object is always shorter than the urp_sendRequest call. + inline ~ClientJob() + { + if( m_bReleaseForTypeDescriptionNecessary ) + typelib_typedescription_release( (typelib_TypeDescription*) m_pInterfaceType ); + uno_releaseIdFromCurrentThread(); + } + + sal_Bool pack(); + void wait(); + sal_Bool extract( ); + void initiate(); + + inline void setBridgePropertyCall() + { m_bBridgePropertyCall = sal_True; } + inline sal_Bool isBridgePropertyCall() + { return m_bBridgePropertyCall; } + inline sal_Bool isOneway() + { return m_bOneway; } + + inline void setUnmarshal( Unmarshal *p ) + { m_pUnmarshal = p; } +public: + typelib_InterfaceMethodTypeDescription *m_pMethodType; + typelib_InterfaceAttributeTypeDescription *m_pAttributeType; + sal_Bool m_bExceptionOccured; + +private: + void **m_ppArgs; + void *m_pReturn; + typelib_InterfaceTypeDescription *m_pInterfaceType; + sal_Bool m_bReleaseForTypeDescriptionNecessary; + + uno_Any **m_ppException; + sal_Bool m_bOneway; + sal_Bool m_bBridgePropertyCall; + sal_uInt16 m_nMethodIndex; + uno_Environment *m_pEnvRemote; + rtl_uString *m_pOid; + sal_Bool m_bCallingConventionForced; +}; + +struct MemberTypeInfo +{ + typelib_InterfaceTypeDescription *m_pInterfaceType; + typelib_InterfaceMethodTypeDescription *m_pMethodType; + typelib_InterfaceAttributeTypeDescription *m_pAttributeType; + sal_Int32 m_nArgCount; + sal_Bool m_bIsReleaseCall; + sal_Bool *m_pbIsIn; + sal_Bool *m_pbIsOut; + sal_Bool m_bIsOneway; + typelib_TypeDescription *m_pReturnType; + typelib_TypeDescription **m_ppArgType; +}; + + +struct ServerJobEntry +{ + rtl_uString *m_pOid; + remote_Interface *m_pRemoteI; + typelib_TypeDescriptionReference *m_pInterfaceTypeRef; + void **m_ppArgs; + void *m_pReturn; + uno_Any m_exception; + uno_Any *m_pException; + remote_Interface *m_pCurrentContext; + sal_Bool m_bHasCurrentContext; + sal_Bool m_bIgnoreCache; +}; + +class ServerMultiJob : private Job +{ +public: + ServerMultiJob( uno_Environment *pEnvRemote, + remote_Context *pContext, + sal_Sequence *pTid, + struct urp_BridgeImpl *pBridgeImpl, + Unmarshal *pUnmarshal, + sal_Int32 nMaxMessages ); + ~ServerMultiJob(); +public: + sal_Bool extract( ); + void initiate(); + void execute(); + +public: + // setMethodType or setAttributeType MUST be called before extract + inline void setMethodType( + typelib_InterfaceMethodTypeDescription *pMethodType, + sal_Bool bIsReleaseCall, + sal_Bool bIsOneway ) + { + m_aTypeInfo[m_nCalls].m_pMethodType = pMethodType; + m_aTypeInfo[m_nCalls].m_pAttributeType = 0; + m_aTypeInfo[m_nCalls].m_nArgCount = pMethodType->nParams; + m_aTypeInfo[m_nCalls].m_bIsReleaseCall = bIsReleaseCall; + m_aTypeInfo[m_nCalls].m_bIsOneway = bIsOneway; + } + + inline void setAttributeType( + typelib_InterfaceAttributeTypeDescription *pAttributeType, sal_Bool bIsSetter, sal_Bool bIsOneway ) + { + m_aTypeInfo[m_nCalls].m_pAttributeType = pAttributeType; + m_aTypeInfo[m_nCalls].m_pMethodType = 0; + m_aTypeInfo[m_nCalls].m_nArgCount = bIsSetter ? 1 : 0; + m_aTypeInfo[m_nCalls].m_bIsReleaseCall = sal_False; + m_aTypeInfo[m_nCalls].m_bIsOneway = bIsOneway; + } + + inline void setType( typelib_TypeDescriptionReference *pTypeRef ) + { + m_aEntries[m_nCalls].m_pInterfaceTypeRef = pTypeRef; + typelib_typedescriptionreference_acquire( m_aEntries[m_nCalls].m_pInterfaceTypeRef ); + TYPELIB_DANGER_GET( + (typelib_TypeDescription ** )&(m_aTypeInfo[m_nCalls].m_pInterfaceType) , + pTypeRef ); + } + // setOid or setInterface MUST be called before extract + inline void setOid( rtl_uString *pOid ) + { + m_aEntries[m_nCalls].m_pOid = pOid; + rtl_uString_acquire( m_aEntries[m_nCalls].m_pOid ); + m_aEntries[m_nCalls].m_pRemoteI = 0; + } + + // setOid or setInterface MUST be called + inline void setInterface( remote_Interface *pRemoteI ) + { + m_aEntries[m_nCalls].m_pRemoteI = pRemoteI; + pRemoteI->acquire( pRemoteI ); + m_aEntries[m_nCalls].m_pOid = 0; + } + + inline void setCurrentContext( + bool bHasCurrentContext, remote_Interface *pCurrentContext ) + { + m_aEntries[m_nCalls].m_pCurrentContext = pCurrentContext; + m_aEntries[m_nCalls].m_bHasCurrentContext = bHasCurrentContext; + } + + inline void setIgnoreCache( sal_Bool bIgnoreCache ) + { + m_aEntries[m_nCalls].m_bIgnoreCache = bIgnoreCache; + } + + inline sal_Bool isFull() + { return m_nCalls >= m_nMaxMessages; } + + inline sal_Int8 *getHeap( sal_Int32 nSizeToAlloc ) + { + if( nSizeToAlloc + m_nCurrentMemPosition > m_nCurrentMemSize ) + { + m_lstMem.push_back( m_pCurrentMem ); + m_nCurrentMemSize = mymax( nSizeToAlloc , MULTIJOB_STANDARD_MEMORY_SIZE ) + + (m_nMaxMessages -m_nCalls)*MULTIJOB_PER_CALL_MEMORY_SIZE; + m_pCurrentMem = (sal_Int8*) rtl_allocateMemory( m_nCurrentMemSize ); + m_nCurrentMemPosition = 0; + } + sal_Int8 *pHeap = m_pCurrentMem + m_nCurrentMemPosition; + m_nCurrentMemPosition += nSizeToAlloc; + + // care for alignment + if( m_nCurrentMemPosition & 0x7 ) + { + m_nCurrentMemPosition = ( ((sal_uInt32)m_nCurrentMemPosition) & ( 0xffffffff - 0x7 )) + 8; + } + return pHeap; + } + void prepareRuntimeException( const ::rtl::OUString &sMessage, sal_Int32 nCall ); + +private: + uno_Environment *m_pEnvRemote; + sal_Int32 m_nCalls; + sal_Int32 m_nMaxMessages; + + ServerJobEntry *m_aEntries; + MemberTypeInfo *m_aTypeInfo; + + sal_Int8 *m_pCurrentMem; + sal_Int32 m_nCurrentMemSize; + sal_Int32 m_nCurrentMemPosition; + + // list of memory pointers, that must be freed + ::std::list< sal_Int8 * > m_lstMem; +}; + + + +//--------------------------------------------------------------------------------------------- +inline ClientJob::ClientJob( + uno_Environment *pEnvRemote, + remote_Context *pContext, + struct urp_BridgeImpl *pBridgeImpl, + rtl_uString *pOid, + typelib_TypeDescription const * pMemberType, + typelib_InterfaceTypeDescription *pInterfaceType, + void *pReturn, + void *ppArgs[], + uno_Any **ppException ) + : Job( + pEnvRemote, pContext, pBridgeImpl, ::bridges_remote::RTC_HOLDENVWEAK ) + , m_ppArgs( ppArgs ) + , m_pReturn( pReturn ) + , m_pInterfaceType( pInterfaceType ) // weak + , m_bReleaseForTypeDescriptionNecessary( sal_False ) + , m_ppException( ppException ) + , m_bBridgePropertyCall( sal_False ) + , m_pEnvRemote( pEnvRemote ) // weak + , m_pOid( pOid ) // weak + , m_bCallingConventionForced( sal_False ) +{ + uno_getIdOfCurrentThread( &m_pTid ); + + if( typelib_TypeClass_INTERFACE_METHOD == pMemberType->eTypeClass ) + { + m_pMethodType = ( typelib_InterfaceMethodTypeDescription * ) pMemberType; + m_pAttributeType = 0; + } + else if( typelib_TypeClass_INTERFACE_ATTRIBUTE == pMemberType->eTypeClass ) + { + m_pAttributeType = ( typelib_InterfaceAttributeTypeDescription * ) pMemberType; + m_pMethodType = 0; + } + else + { + OSL_ASSERT( ! "wrong member type" ); + } + + // calculate method index + if( ! m_pInterfaceType->aBase.bComplete ) + { + // must be acquired because typedescription may be exchanged + typelib_typedescription_acquire((typelib_TypeDescription*) m_pInterfaceType ); + m_bReleaseForTypeDescriptionNecessary = sal_True; + typelib_typedescription_complete( (typelib_TypeDescription ** ) &m_pInterfaceType ); + } + m_nMethodIndex = (sal_uInt16) m_pInterfaceType->pMapMemberIndexToFunctionIndex[ + ((typelib_InterfaceMemberTypeDescription*)pMemberType)->nPosition ]; + + if( m_pAttributeType && m_ppArgs ) + { + // setter + m_nMethodIndex ++; + } + + if( typelib_TypeClass_INTERFACE_METHOD == pMemberType->eTypeClass ) + { +// if( (( typelib_InterfaceMemberTypeDescription * ) pMemberType)->nPosition +// == REMOTE_RELEASE_METHOD_INDEX ) +// { +// m_bOneway = sal_True; +// } +// else + if( pBridgeImpl->m_properties.bForceSynchronous ) + { + m_bOneway = sal_False; + if( (( typelib_InterfaceMethodTypeDescription * ) pMemberType)->bOneWay ) + { + m_bCallingConventionForced = sal_True; + } + } + else + { + m_bOneway = (( typelib_InterfaceMethodTypeDescription * ) pMemberType)->bOneWay; + } + } + else + { + m_bOneway = sal_False; + } +} + +} +#endif diff --git a/bridges/source/remote/urp/urp_log.cxx b/bridges/source/remote/urp/urp_log.cxx new file mode 100644 index 000000000000..5813f917d7da --- /dev/null +++ b/bridges/source/remote/urp/urp_log.cxx @@ -0,0 +1,147 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <osl/time.h> +#include "urp_bridgeimpl.hxx" +#include "urp_log.hxx" + +using namespace ::rtl; +using namespace ::osl; +namespace bridges_urp +{ +#ifdef BRIDGES_URP_PROT + Mutex g_logFileMutex; + + class FileAccess + { + public: + FileAccess( urp_BridgeImpl *pBridgeImpl_ ) : + pBridgeImpl( pBridgeImpl_ ), + guard( g_logFileMutex ) + { + if( pBridgeImpl->m_pLogFile ) + { + f = pBridgeImpl->m_pLogFile; + } + else + { + f = fopen( pBridgeImpl->m_sLogFileName.getStr() , "a" ); + } + } + ~FileAccess() + { + if( ! pBridgeImpl->m_pLogFile ) + { + fclose( f ); + } + } + FILE *getFile() + { + return f; + } + private: + urp_BridgeImpl *pBridgeImpl; + MutexGuard guard; + FILE *f; + }; + + void urp_logCall( urp_BridgeImpl *pBridgeImpl, sal_Int32 nSize, sal_Int32 nUseData, sal_Bool bSynchron , + const ::rtl::OUString &sMethodName ) + { + if( pBridgeImpl->m_sLogFileName.getLength() && getenv( "PROT_REMOTE_ACTIVATE" ) ) + { + OString sOperation = OUStringToOString( sMethodName,RTL_TEXTENCODING_ASCII_US ); + + FileAccess access( pBridgeImpl ); + fprintf( access.getFile() , + "%06u: calling [size=%d(usedata=%d)] [synchron=%d] [name=%s]\n" , + static_cast< unsigned int > (osl_getGlobalTimer()), + static_cast< int > (nSize), + static_cast< int > (nUseData), + bSynchron, sOperation.pData->buffer ); + } + } + + void urp_logServingRequest( urp_BridgeImpl *pBridgeImpl, + sal_Int32 nSize, sal_Int32 nUseData, sal_Bool bSynchron , + const ::rtl::OUString &sMethodName ) + { + if( pBridgeImpl->m_sLogFileName.getLength() && getenv( "PROT_REMOTE_ACTIVATE" ) ) + { + OString sOperation = OUStringToOString( sMethodName,RTL_TEXTENCODING_ASCII_US ); + + FileAccess access( pBridgeImpl ); + fprintf( + access.getFile(), + "%06u: serving request [size=%d(usedata=%d)] [synchron=%d] [name=%s]\n", + static_cast< unsigned int > (osl_getGlobalTimer()), + static_cast< int > (nSize), + static_cast< int > (nUseData), + bSynchron, + sOperation.pData->buffer + ); + } + } + + void urp_logGettingReply( urp_BridgeImpl *pBridgeImpl, + sal_Int32 nSize, sal_Int32 nUseData, + const ::rtl::OUString &sMethodName ) + { + if( pBridgeImpl->m_sLogFileName.getLength() && getenv( "PROT_REMOTE_ACTIVATE" ) ) + { + OString sOperation = OUStringToOString( sMethodName,RTL_TEXTENCODING_ASCII_US ); + FileAccess access( pBridgeImpl ); + fprintf( access.getFile(), + "%06u: getting reply [size=%d(usedata=%d)][name=%s]\n" , + static_cast< unsigned int > (osl_getGlobalTimer()), + static_cast< int > (nSize), + static_cast< int > (nUseData), + sOperation.pData->buffer); + } + } + + void urp_logReplying( urp_BridgeImpl *pBridgeImpl, + sal_Int32 nSize , sal_Int32 nUseData, + const ::rtl::OUString &sMethodName ) + { + if( pBridgeImpl->m_sLogFileName.getLength() && getenv( "PROT_REMOTE_ACTIVATE" ) ) + { + OString sOperation = OUStringToOString(sMethodName,RTL_TEXTENCODING_ASCII_US); + + FileAccess access( pBridgeImpl ); + fprintf( access.getFile(), + "%06u: replying [size=%d(usedata=%d)] [name=%s]\n", + static_cast< unsigned int > (osl_getGlobalTimer()), + static_cast< int > (nSize), + static_cast< int > (nUseData), + sOperation.pData->buffer); + } + } +#endif +} diff --git a/bridges/source/remote/urp/urp_log.hxx b/bridges/source/remote/urp/urp_log.hxx new file mode 100644 index 000000000000..486ff90c1e92 --- /dev/null +++ b/bridges/source/remote/urp/urp_log.hxx @@ -0,0 +1,50 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +namespace bridges_urp +{ +#ifdef DBG_UTIL +#define BRIDGES_URP_PROT +#endif + +#ifdef BRIDGES_URP_PROT + void urp_logCall( urp_BridgeImpl *pBridgeImpl , + sal_Int32 nSize, sal_Int32 nUseData, sal_Bool bSynchron , + const ::rtl::OUString &sMethodName ); + + void urp_logServingRequest( urp_BridgeImpl *pBridgeImpl, + sal_Int32 nSize, sal_Int32 nUseData, sal_Bool bSynchron , + const ::rtl::OUString &sMethodName ); + + void urp_logGettingReply( urp_BridgeImpl *pBridgeImpl, + sal_Int32 nSize, sal_Int32 nUseData, + const ::rtl::OUString &sMethodName ); + + void urp_logReplying( urp_BridgeImpl *pBridgeImpl, + sal_Int32 nSize , sal_Int32 nUseData, + const ::rtl::OUString &sMethodName ); +#endif +} diff --git a/bridges/source/remote/urp/urp_marshal.cxx b/bridges/source/remote/urp/urp_marshal.cxx new file mode 100644 index 000000000000..7545018ea57f --- /dev/null +++ b/bridges/source/remote/urp/urp_marshal.cxx @@ -0,0 +1,235 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <string.h> +#include <osl/diagnose.h> +#include <rtl/alloc.h> + +#include <uno/any2.h> +#include <uno/sequence2.h> + +#include "urp_marshal.hxx" + +using namespace ::rtl; + +using namespace ::com::sun::star::uno; + +namespace bridges_urp { + +static int g_nDetectLittleEndian = 1; +char g_bMarshalSystemIsLittleEndian = ((char*)&g_nDetectLittleEndian)[0]; + +Marshal::Marshal( urp_BridgeImpl *pBridgeImpl, + sal_Int32 nBufferSize, + urp_extractOidCallback callback) : + m_nBufferSize( nBufferSize ), + m_base( (sal_Int8*)rtl_allocateMemory( nBufferSize ) ), + m_pos( m_base + 2*sizeof( sal_Int32 ) ), + m_pBridgeImpl( pBridgeImpl ), + m_callback( callback ) +{} + +Marshal::~Marshal( ) +{ + rtl_freeMemory( m_base ); +} + +void Marshal::packOid( const ::rtl::OUString & oid ) +{ + sal_uInt16 nIndex; + if( oid.getLength() ) + { + nIndex = m_pBridgeImpl->m_oidCacheOut.seek( oid ); + if( 0xffff == nIndex ) + { + nIndex = m_pBridgeImpl->m_oidCacheOut.put( oid ); + packString( (void*)(&oid.pData) ); + } + else + { + OUString dummy; + packString( &dummy ); + } + } + else + { + // null reference + nIndex = 0xffff; + OUString dummy; + packString( &dummy ); + } + packInt16( &nIndex ); +} + +void Marshal::packTid( const ByteSequence & threadId, sal_Bool bIgnoreCache ) +{ + + sal_uInt16 nIndex = 0xffff; + if( ! bIgnoreCache ) + { + nIndex = m_pBridgeImpl->m_tidCacheOut.seek( threadId ); + } + + if( 0xffff == nIndex ) + { + if( ! bIgnoreCache ) + { + nIndex = m_pBridgeImpl->m_tidCacheOut.put( threadId ); + } + packByteSequence( (sal_Int8*) threadId.getConstArray() ,threadId.getLength()); + } + else + { + packByteSequence( 0 , 0 ); + } + packInt16( &nIndex ); +} + + +void Marshal::packType( void *pSource ) +{ + typelib_TypeDescriptionReference *pRef = + *(typelib_TypeDescriptionReference ** ) pSource; + + OSL_ASSERT( pRef ); + + sal_uInt8 nTypeClass = ( sal_uInt8 ) pRef->eTypeClass; + + if( nTypeClass <= /* any*/ 14 ) + { + packInt8( (sal_Int8*)&nTypeClass ); + } + else + { + OUString sTypeName; + sal_uInt16 nIndex = 0xffff; + + nIndex = m_pBridgeImpl->m_typeCacheOut.seek( *(Type*)&pRef ); + if( 0xffff == nIndex ) + { + // put it into the cache + nIndex = m_pBridgeImpl->m_typeCacheOut.put( *(Type*)&pRef ); + sTypeName = pRef->pTypeName; + nTypeClass = nTypeClass | 0x80; + } + packInt8( &nTypeClass ); + packInt16( &nIndex ); + if( 0x80 & nTypeClass ) + { + packString( &sTypeName ); + } + } +} + +sal_Bool Marshal::packRecursive( void *pSource , typelib_TypeDescription *pType ) +{ + sal_Bool bSuccess = sal_True; + switch( pType->eTypeClass ) + { + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_STRUCT: + { + typelib_CompoundTypeDescription * pCompType = (typelib_CompoundTypeDescription*)pType; + + if (pCompType->pBaseTypeDescription) + { + bSuccess = pack( pSource , (typelib_TypeDescription*) pCompType->pBaseTypeDescription ); + } + + // then construct members + typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs; + sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets; + sal_Int32 nDescr = pCompType->nMembers; + + for ( sal_Int32 nPos = 0; nPos < nDescr; ++nPos ) + { + typelib_TypeDescription * pMemberType = 0; + TYPELIB_DANGER_GET( &pMemberType, ppTypeRefs[nPos] ); + if( pMemberType ) + { + bSuccess = bSuccess && pack( (char*)pSource + pMemberOffsets[nPos] , pMemberType ); + TYPELIB_DANGER_RELEASE( pMemberType ); + } + else + { + OUStringBuffer buf( 64 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("Couldn't get typedescription for type ")); + buf.append( ppTypeRefs[nPos]->pTypeName ); + m_pBridgeImpl->addError( buf.makeStringAndClear() ); + bSuccess = sal_False; + } + } + break; + } + case typelib_TypeClass_SEQUENCE: + { + typelib_IndirectTypeDescription *pIndirectType = + ( typelib_IndirectTypeDescription* ) pType; + + const sal_Int32 nElements = (*(uno_Sequence **)pSource)->nElements; + char * pSourceElements = (char *)(*(uno_Sequence **)pSource)->elements; + + if( typelib_TypeClass_BYTE == pIndirectType->pType->eTypeClass ) + { + // Byte sequences are optimized + packByteSequence( (sal_Int8*)pSourceElements , nElements ); + } + else + { + typelib_TypeDescription *pElementType = 0; + TYPELIB_DANGER_GET( &pElementType, pIndirectType->pType ); + if( pElementType ) + { + const sal_Int32 nElementSize = pElementType->nSize; + + packCompressedSize( nElements ); + for ( sal_Int32 i = 0 ; i < nElements; i++ ) + { + bSuccess = bSuccess && pack( pSourceElements + (nElementSize*i) , pElementType ); + } + TYPELIB_DANGER_RELEASE( pElementType ); + } + else + { + bSuccess = sal_False; + OUStringBuffer buf( 64 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("Couldn't get typedescription for type ")); + buf.append( pIndirectType->pType->pTypeName ); + m_pBridgeImpl->addError( buf.makeStringAndClear() ); + } + } + break; + } + default: + OSL_ASSERT( 0 ); + } + return bSuccess; +} + +} // end namespace bridges diff --git a/bridges/source/remote/urp/urp_marshal.hxx b/bridges/source/remote/urp/urp_marshal.hxx new file mode 100644 index 000000000000..95812b1a695d --- /dev/null +++ b/bridges/source/remote/urp/urp_marshal.hxx @@ -0,0 +1,343 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _URP_MARSHAL_HXX_ +#define _URP_MARSHAL_HXX_ +#include <rtl/ustrbuf.hxx> +#include <rtl/byteseq.hxx> +#include <com/sun/star/uno/Type.hxx> +#include "urp_bridgeimpl.hxx" +#include "urp_marshal_decl.hxx" + +#include <string.h> + +struct remote_Interface; + +namespace bridges_urp +{ + // methods for accessing marshaling buffer + inline void Marshal::finish( sal_Int32 nMessageCount ) + { + sal_Int32 nSize = getSize() - 2*sizeof( sal_Int32 ); + + // save the state + sal_Int8 *pos = m_pos; + m_pos = m_base; + packInt32( &nSize ); + packInt32( &nMessageCount ); + + // reset the state + m_pos = pos; + } + + inline void Marshal::restart() + { + m_pos = m_base + 2*sizeof( sal_Int32 ); + } + + inline sal_Int8 *Marshal::getBuffer() + { + return m_base; + } + + inline sal_Bool Marshal::empty() const + { + return ( m_pos - m_base ) == 2*sizeof( sal_Int32 ); + } + + inline sal_Int32 Marshal::getSize() + { + return ((sal_Int32) (m_pos - m_base)); + } + + inline void Marshal::ensureAdditionalMem( sal_Int32 nMemToAdd ) + { + sal_Int32 nDiff = m_pos - m_base; + if( nDiff + nMemToAdd > m_nBufferSize ) + { + m_nBufferSize = m_nBufferSize * 2 > nDiff + nMemToAdd ? + m_nBufferSize* 2 : + nDiff + nMemToAdd; + + m_base = ( sal_Int8 * ) rtl_reallocateMemory( m_base , m_nBufferSize ); + m_pos = m_base + nDiff; + } + } + + // marshaling methods + inline void Marshal::packInt8( void *pSource ) + { + ensureAdditionalMem( 1 ); + *m_pos = *((sal_Int8*) pSource ); + m_pos++; + } + + inline void Marshal::packInt16( void *pSource ) + { + ensureAdditionalMem( 2 ); + if( isSystemLittleEndian() ) + { + m_pos[0] = ((unsigned char *)pSource)[1]; + m_pos[1] = ((unsigned char *)pSource)[0]; + } + else + { + m_pos[1] = ((unsigned char *)pSource)[1]; + m_pos[0] = ((unsigned char *)pSource)[0]; + } + m_pos +=2; + } + + inline void Marshal::packByteSequence( sal_Int8 *pData , sal_Int32 nLength ) + { + packCompressedSize( nLength ); + + ensureAdditionalMem( nLength ); + memcpy( m_pos , pData , nLength ); + m_pos += nLength; + } + + inline void Marshal::packString( void *pSource ) + { + rtl_uString *p = *( rtl_uString ** ) pSource; + + // to be optimized ! + // static buffer in marshal + ::rtl::OString o = ::rtl::OUStringToOString( p , RTL_TEXTENCODING_UTF8 ); + sal_Int32 nLength = o.pData->length; + packCompressedSize( nLength ); + + ensureAdditionalMem( nLength ); + + memcpy( m_pos , o.pData->buffer , nLength ); + m_pos += nLength; + } + + inline sal_Bool Marshal::packAny( void *pSource ) + { + sal_Bool bSuccess = sal_True; + uno_Any *pAny = (uno_Any * ) pSource; + + // pack the type + packType( &( pAny->pType ) ); + // pack the value + typelib_TypeDescription *pType = 0; + TYPELIB_DANGER_GET( &pType, pAny->pType ); + if( pType ) + { + pack( pAny->pData , pType ); + TYPELIB_DANGER_RELEASE( pType ); + } + else + { + rtl::OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("couldn't get typedescription for type " ) ); + buf.append( pAny->pType->pTypeName ); + m_pBridgeImpl->addError( buf.makeStringAndClear() ); + bSuccess = sal_False; + } + return bSuccess; + } + + inline void Marshal::packInt32( void *pSource ) + { + ensureAdditionalMem( 4 ); + if( isSystemLittleEndian() ) + { + m_pos[0] = ((unsigned char *)pSource)[3]; + m_pos[1] = ((unsigned char *)pSource)[2]; + m_pos[2] = ((unsigned char *)pSource)[1]; + m_pos[3] = ((unsigned char *)pSource)[0]; + } + else { + m_pos[3] = ((unsigned char *)pSource)[3]; + m_pos[2] = ((unsigned char *)pSource)[2]; + m_pos[1] = ((unsigned char *)pSource)[1]; + m_pos[0] = ((unsigned char *)pSource)[0]; + } + m_pos +=4; + } + + inline void Marshal::packCompressedSize( sal_Int32 nSize ) + { + ensureAdditionalMem( 5 ); + + if( nSize < 0xff ) + { + *((sal_uInt8*)m_pos) = (sal_uInt8) nSize; + m_pos ++; + } + else + { + *((sal_uInt8*)m_pos) = 0xff; + m_pos ++; + packInt32( &nSize ); + } + } + + inline sal_Bool Marshal::pack( void *pSource , typelib_TypeDescription *pType ) + { + sal_Bool bSuccess = sal_True; + switch( pType->eTypeClass ) + { + case typelib_TypeClass_BYTE: + { + packInt8( pSource ); + break; + } + case typelib_TypeClass_BOOLEAN: + { + ensureAdditionalMem( 1 ); + *m_pos = ( *((sal_Bool*) pSource ) ) ? 1 : 0; + m_pos++; + break; + } + + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + { + packInt16( pSource ); + break; + } + case typelib_TypeClass_ENUM: + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + case typelib_TypeClass_FLOAT: + { + packInt32( pSource ); + break; + } + case typelib_TypeClass_DOUBLE: + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + { + ensureAdditionalMem( 8 ); + if( isSystemLittleEndian() ) + { + m_pos[0] = ((unsigned char *)pSource)[7]; + m_pos[1] = ((unsigned char *)pSource)[6]; + m_pos[2] = ((unsigned char *)pSource)[5]; + m_pos[3] = ((unsigned char *)pSource)[4]; + m_pos[4] = ((unsigned char *)pSource)[3]; + m_pos[5] = ((unsigned char *)pSource)[2]; + m_pos[6] = ((unsigned char *)pSource)[1]; + m_pos[7] = ((unsigned char *)pSource)[0]; + } + else + { + m_pos[7] = ((unsigned char *)pSource)[7]; + m_pos[6] = ((unsigned char *)pSource)[6]; + m_pos[5] = ((unsigned char *)pSource)[5]; + m_pos[4] = ((unsigned char *)pSource)[4]; + m_pos[3] = ((unsigned char *)pSource)[3]; + m_pos[2] = ((unsigned char *)pSource)[2]; + m_pos[1] = ((unsigned char *)pSource)[1]; + m_pos[0] = ((unsigned char *)pSource)[0]; + } + m_pos += 8; + break; + } + + case typelib_TypeClass_STRING: + { + packString( pSource ); + break; + } + case typelib_TypeClass_TYPE: + { + packType( pSource ); + break; + } + case typelib_TypeClass_ANY: + { + bSuccess = packAny( pSource ); + break; + } + case typelib_TypeClass_TYPEDEF: + { + bSuccess = sal_False; + m_pBridgeImpl->addError( "can't handle typedef typedescriptions" ); + break; + } + case typelib_TypeClass_INTERFACE: + { + remote_Interface *pRemoteI = *( remote_Interface ** )pSource; + + ::rtl::OUString sOid; + sal_uInt16 nIndex = 0xffff; + if( pRemoteI ) + { + m_callback( pRemoteI , &(sOid.pData) ); + + nIndex = m_pBridgeImpl->m_oidCacheOut.seek( sOid ); + if( 0xffff == nIndex ) + { + nIndex = m_pBridgeImpl->m_oidCacheOut.put( sOid ); + } + else + { + // cached ! + sOid = ::rtl::OUString(); + } + } + packString( &sOid ); + packInt16( &nIndex ); + break; + } + case typelib_TypeClass_VOID: + { + // do nothing + break; + } + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_SEQUENCE: + { + bSuccess = packRecursive( pSource, pType ); + break; + } + default: + { + bSuccess = sal_False; + rtl::OUStringBuffer buf( 128 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "can't handle values with typeclass " ) ); + buf.append( (sal_Int32 ) pType->eTypeClass , 10 ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " (" ) ); + buf.append( pType->pTypeName ); + buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ")" ) ); + m_pBridgeImpl->addError( buf.makeStringAndClear() ); + break; + } + } + return bSuccess; + } +} + + + +#endif + diff --git a/bridges/source/remote/urp/urp_marshal_decl.hxx b/bridges/source/remote/urp/urp_marshal_decl.hxx new file mode 100644 index 000000000000..133760bb33e3 --- /dev/null +++ b/bridges/source/remote/urp/urp_marshal_decl.hxx @@ -0,0 +1,106 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _URP_MARSHAL_DECL_HXX_ +#define _URP_MARSHAL_DECL_HXX_ + +#include <rtl/ustring.hxx> +#include <rtl/byteseq.hxx> + +#include <com/sun/star/uno/Type.hxx> + +namespace bridges_urp +{ + struct urp_BridgeImpl; + + typedef void + ( SAL_CALL * urp_extractOidCallback )( remote_Interface *pRemoteI, rtl_uString **ppOid ); + + extern char g_bMarshalSystemIsLittleEndian; + class Marshal + { + public: + Marshal( /* cache access */ struct urp_BridgeImpl *, + sal_Int32 m_nBufferSize, + urp_extractOidCallback callback = 0 + ); + ~Marshal( ); + + inline sal_Bool pack( void *pSource , typelib_TypeDescription *pType ); + + sal_Bool packRecursive( void *pSource, typelib_TypeDescription *pType ); + + void packTid( const ::rtl::ByteSequence &id, sal_Bool bIgnoreCache = sal_False ); + void packOid( const ::rtl::OUString &oid ); + void packType( void *pSource ); + + inline void packCompressedSize( sal_Int32 nSize ); + inline void packInt8( void *pSource ); + inline void packInt16( void *pSource ); + inline void packInt32( void *pSource ); + inline void packString( void *pSource ); + inline sal_Bool packAny( void *pSource ); + inline void packByteSequence( sal_Int8 *pBuffer , sal_Int32 nSize ); + + // can be called during marshaling, but not between + // finish and restart + // returns true, when nothing has been marshaled + inline sal_Bool empty() const; + + // stops marshaling, inserts size in front of the buffer + // getStart and getSize can now be called + inline void finish( sal_Int32 nMessageCount ); + + // must be called after finish. After calling restart, + // a new marshalling session is started invalidating + // the previous bufer + inline void restart(); + + // is only valid, after finish has been called. + // valid until destructed. + inline sal_Int8 *getBuffer(); + + // is only valid, after finish has been called. + // valid until destructed. + inline sal_Int32 getSize(); + + inline sal_Int32 getPos() + { return m_pos - m_base; } + + inline sal_Bool isSystemLittleEndian() + { return g_bMarshalSystemIsLittleEndian; } + + private: + inline void ensureAdditionalMem( sal_Int32 nMemToAdd ); + sal_Int32 m_nBufferSize; + sal_Int8 *m_base; + sal_Int8 *m_pos; + struct urp_BridgeImpl *m_pBridgeImpl; + urp_extractOidCallback m_callback; + }; +} +#endif diff --git a/bridges/source/remote/urp/urp_property.hxx b/bridges/source/remote/urp/urp_property.hxx new file mode 100644 index 000000000000..59dbe3f22f93 --- /dev/null +++ b/bridges/source/remote/urp/urp_property.hxx @@ -0,0 +1,93 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _URP_PROPERTY_HXX_ +#define _URP_PROPERTY_HXX_ +#ifndef _BRIDGES_REMOTE_REMOTE_H_ +#include <bridges/remote/remote.h> +#endif +#include <rtl/ustring.hxx> +#include <rtl/byteseq.hxx> + +namespace bridges_urp +{ + struct Properties + { + ::rtl::ByteSequence seqBridgeID; + sal_Int32 nTypeCacheSize; + sal_Int32 nOidCacheSize; + sal_Int32 nTidCacheSize; + ::rtl::OUString sSupportedVersions; + ::rtl::OUString sVersion; + sal_Int32 nFlushBlockSize; + sal_Int32 nOnewayTimeoutMUSEC; + sal_Bool bSupportsMustReply; + sal_Bool bSupportsSynchronous; + sal_Bool bSupportsMultipleSynchronous; + sal_Bool bClearCache; + sal_Bool bNegotiate; + sal_Bool bForceSynchronous; + sal_Bool bCurrentContext; + + inline Properties() + : nTypeCacheSize( 256 ) + , nOidCacheSize( 256 ) + , nTidCacheSize( 256 ) + , sSupportedVersions( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "1.0" ) ) ) + , sVersion( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "1.0" ))) + , nFlushBlockSize( 4*1024 ) + , nOnewayTimeoutMUSEC( 10000 ) + , bSupportsMustReply( sal_False ) + , bSupportsSynchronous( sal_False ) + , bSupportsMultipleSynchronous( sal_False ) + , bClearCache( sal_False ) + , bNegotiate( sal_True ) + , bForceSynchronous( sal_True ) + , bCurrentContext( sal_False ) + {} + + inline Properties & SAL_CALL operator = ( const Properties &props ) + { + seqBridgeID = props.seqBridgeID; + nTypeCacheSize = props.nTypeCacheSize; + nOidCacheSize = props.nOidCacheSize; + nTidCacheSize = props.nTidCacheSize; + sSupportedVersions = props.sSupportedVersions; + sVersion = props.sVersion; + nFlushBlockSize = props.nFlushBlockSize; + nOnewayTimeoutMUSEC = props.nOnewayTimeoutMUSEC; + bSupportsMustReply = props.bSupportsMustReply; + bSupportsSynchronous = props.bSupportsSynchronous; + bSupportsMultipleSynchronous = props.bSupportsMultipleSynchronous; + bClearCache = props.bClearCache; + bNegotiate = props.bNegotiate; + bForceSynchronous = props.bForceSynchronous; + bCurrentContext = props.bCurrentContext; + return *this; + } + }; +} // end namespace bridges_urp +#endif diff --git a/bridges/source/remote/urp/urp_propertyobject.cxx b/bridges/source/remote/urp/urp_propertyobject.cxx new file mode 100644 index 000000000000..94d3e7edee0a --- /dev/null +++ b/bridges/source/remote/urp/urp_propertyobject.cxx @@ -0,0 +1,793 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <stdlib.h> +#include <osl/diagnose.h> + +#include <rtl/random.h> + +#include <uno/data.h> + +#include "com/sun/star/bridge/InvalidProtocolChangeException.hpp" +#include <com/sun/star/bridge/XProtocolProperties.hpp> + +#include "urp_propertyobject.hxx" +#include "urp_dispatch.hxx" +#include "urp_bridgeimpl.hxx" +#include "urp_job.hxx" + +using namespace ::rtl; +using namespace ::osl; +using namespace ::com::sun::star::bridge; +using namespace ::com::sun::star::uno; + +using namespace bridges_urp; + +extern "C" { + +static void SAL_CALL staticAcquire( remote_Interface *pRemoteI ) +{ + PropertyObject *pProperties = (PropertyObject *) pRemoteI; + pProperties->thisAcquire(); +} + +static void SAL_CALL staticRelease( remote_Interface *pRemoteI ) +{ + PropertyObject *pProperties = (PropertyObject *) pRemoteI; + pProperties->thisRelease(); +} + +static void SAL_CALL staticDispatch( + remote_Interface * pRemoteI, typelib_TypeDescription const * pMemberType, + void * pReturn, void * pArgs[], uno_Any ** ppException ) +{ + PropertyObject *pProperties = (PropertyObject *) pRemoteI; + pProperties->thisDispatch( pMemberType, pReturn, pArgs, ppException ); +} + +} + +namespace bridges_urp +{ +// some nice constants .... +static const sal_Int32 METHOD_QUERY_INTERFACE = 0; +static const sal_Int32 METHOD_GET_PROPERTIES = 3; +static const sal_Int32 METHOD_REQUEST_CHANGE = 4; +static const sal_Int32 METHOD_COMMIT_CHANGE = 5; + +static const sal_Int32 PROPERTY_BRIDGEID = 0; +static const sal_Int32 PROPERTY_TYPECACHESIZE = 1; +static const sal_Int32 PROPERTY_OIDCACHESIZE = 2; +static const sal_Int32 PROPERTY_TIDCACHESIZE = 3; +static const sal_Int32 PROPERTY_SUPPORTEDVERSIONS = 4; +static const sal_Int32 PROPERTY_VERSION =5; +static const sal_Int32 PROPERTY_FLUSHBLOCKSIZE = 6; +static const sal_Int32 PROPERTY_ONEWAYTIMEOUT_MUSEC = 7; +static const sal_Int32 PROPERTY_SUPPORTSMUSTREPLY = 8; +static const sal_Int32 PROPERTY_SUPPERTSSYNCHRONOUS = 9; +static const sal_Int32 PROPERTY_SUPPORTSMULTIPLESYNCHRONOUS = 10; +static const sal_Int32 PROPERTY_CLEARCACHE = 11; +static const sal_Int32 PROPERTY_NEGOTIATE = 12; +static const sal_Int32 PROPERTY_FORCESYNCHRONOUS = 13; +static const sal_Int32 PROPERTY_CURRENTCONTEXT = 14; + +static const sal_Int32 MAX_PROPERTIES = PROPERTY_CURRENTCONTEXT +1; + +const sal_Char *g_aPropertyName[] = +{ + "BridgeId", + "TypeCacheSize", + "OidCacheSize", + "TidCacheSize", + "SupportedVersion", + "Version", + "FlushBlockSize", + "OnewayTimeoutMUSEC", + "SupportsMustReply", + "SupportsSynchronous", + "SupportsMultipleSynchronous", + "ClearCache", + "Negotiate", + "ForceSynchronous", + "CurrentContext" +}; + +// nice little helper functions for conversion +template< class t > +void assignToIdl( ProtocolProperty *pIdl, sal_Int32 nIndex, const t &value ) +{ + pIdl->Name = OUString::createFromAscii( g_aPropertyName[nIndex] ); + ( *(::com::sun::star::uno::Any *)&(pIdl->Value) ) <<= value; +} + +template< class t > +void assignFromIdl( t * p, const ProtocolProperty & property ) +{ + property.Value >>=*p; +} + +static sal_Int32 getIndexFromIdl( const ProtocolProperty & property ) +{ + sal_Int32 nResult = -1; + for( sal_Int32 i = 0 ; i < MAX_PROPERTIES ; i ++ ) + { + if( 0 == property.Name.compareToAscii( g_aPropertyName[i] ) ) + { + nResult = i; + break; + } + } + return nResult; +} + +static sal_Int32 getIndexFromString( const OUString & property ) +{ + sal_Int32 nResult = -1; + for( sal_Int32 i = 0 ; i < MAX_PROPERTIES ; i ++ ) + { + if( 0 == property.compareToAscii( g_aPropertyName[i] ) ) + { + nResult = i; + break; + } + } + return nResult; +} + +static sal_Bool assignFromIdlToStruct( Properties *pProps, const ProtocolProperty &idl ) +{ + sal_Bool bReturn = sal_True; + + sal_Int32 nIndex = getIndexFromIdl( idl ); + if( nIndex >= 0 ) + { + switch( nIndex ) + { + case PROPERTY_SUPPORTSMULTIPLESYNCHRONOUS: + assignFromIdl( &(pProps->bSupportsMultipleSynchronous) , idl ); + break; + case PROPERTY_SUPPERTSSYNCHRONOUS: + assignFromIdl( &(pProps->bSupportsMustReply) , idl ); + break; + case PROPERTY_SUPPORTSMUSTREPLY: + assignFromIdl( &(pProps->bSupportsSynchronous) , idl ); + break; + case PROPERTY_ONEWAYTIMEOUT_MUSEC: + assignFromIdl( &(pProps->nOnewayTimeoutMUSEC) , idl ); + break; + case PROPERTY_BRIDGEID: + assignFromIdl( (Sequence< sal_Int8 > * )&(pProps->seqBridgeID), idl ); + break; + case PROPERTY_TYPECACHESIZE: + assignFromIdl( &(pProps->nTypeCacheSize) , idl ); + break; + case PROPERTY_OIDCACHESIZE: + assignFromIdl( &(pProps->nOidCacheSize) , idl ); + break; + case PROPERTY_TIDCACHESIZE: + assignFromIdl( &(pProps->nTidCacheSize), idl ); + break; + case PROPERTY_SUPPORTEDVERSIONS: + assignFromIdl( &(pProps->sSupportedVersions) , idl ); + break; + case PROPERTY_VERSION: + assignFromIdl( &(pProps->sVersion) , idl ); + break; + case PROPERTY_FLUSHBLOCKSIZE: + assignFromIdl( &(pProps->nFlushBlockSize) ,idl ); + break; + case PROPERTY_CLEARCACHE: + assignFromIdl( &(pProps->bClearCache) ,idl ); + break; + case PROPERTY_NEGOTIATE: + assignFromIdl( &(pProps->bNegotiate) ,idl ); + break; + case PROPERTY_FORCESYNCHRONOUS: + assignFromIdl( &(pProps->bForceSynchronous) ,idl ); + break; + case PROPERTY_CURRENTCONTEXT: + pProps->bCurrentContext = true; + break; + default: + bReturn = sal_False; + } + } + else + { + bReturn = sal_False; + } + return bReturn; +} + +static void extractTokens( + const ::rtl::OUString &sProps , ::std::list< OUString > &lst ) +{ + sal_Int32 nNext = 0; + while ( sal_True ) + { + sal_Int32 nStart = nNext; + nNext = sProps.indexOf( ',' , nNext ); + if( -1 == nNext ) + { + lst.push_back( sProps.copy( nStart, sProps.getLength() - nStart ) ); + break; + } + lst.push_back( sProps.copy( nStart , nNext - nStart ) ); + nNext ++; + } +} + + +static void assignFromStringToPropSeq( const OUString &sProps, uno_Sequence **ppPropertySeq) +{ + ::std::list< OUString > lst; + extractTokens( sProps , lst ); + + typelib_TypeDescription *pSequenceType = 0; + getCppuType( (Sequence< ProtocolProperty > *)0).getDescription( &pSequenceType ); + uno_Sequence *pSeq = 0; + uno_sequence_construct( &pSeq , pSequenceType , 0, lst.size() , 0 ); + ProtocolProperty *pElements = (ProtocolProperty * ) pSeq->elements; + + sal_Int32 i = 0; + for( ::std::list< OUString >::iterator ii = lst.begin() ; ii != lst.end() ; ++ ii, i++ ) + { + sal_Int32 nAssign = (*ii).indexOf( '=' ); + if( -1 == nAssign ) + { + OString o = OUStringToOString( *ii, RTL_TEXTENCODING_ASCII_US ); + OSL_ENSURE( !"wrong protocol propertyt format, ignored", o.getStr() ); + } + OUString sPropName = (*ii).copy( 0, nAssign ); + OUString sValue = (*ii).copy( nAssign +1, (*ii).getLength() - nAssign -1 ); + + sal_Int32 nIndex = getIndexFromString( sPropName ); + if( -1 == nIndex ) + { + OString o = OUStringToOString( sPropName , RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE( !"unknown protocol property, ignored", o.getStr() ); + } + switch( nIndex ) + { + // voids + case PROPERTY_CURRENTCONTEXT: + pElements[i].Name = OUString::createFromAscii( + g_aPropertyName[nIndex] ); + break; + // bools + case PROPERTY_CLEARCACHE: + case PROPERTY_NEGOTIATE: + case PROPERTY_FORCESYNCHRONOUS: + { + sal_Bool bClearCache = (sal_Bool ) sValue.toInt32(); + assignToIdl( &(pElements[i]) , nIndex , bClearCache ); + break; + } + // ints + case PROPERTY_TYPECACHESIZE: + case PROPERTY_OIDCACHESIZE: + case PROPERTY_TIDCACHESIZE: + case PROPERTY_FLUSHBLOCKSIZE: + case PROPERTY_ONEWAYTIMEOUT_MUSEC: + { + sal_Int32 nValue = sValue.toInt32(); + assignToIdl( &(pElements[i]) , nIndex , nValue ); + break; + } + + // strings + case PROPERTY_VERSION: + assignToIdl( &(pElements[i]) , nIndex , sValue ); + break; + default: + OString o = OUStringToOString( sPropName, RTL_TEXTENCODING_ASCII_US ); + OSL_ENSURE( !"readonly protocol property, ignored" , o.getStr() ); + } + } + *ppPropertySeq = pSeq; + typelib_typedescription_release( pSequenceType ); +} + +static void assignFromPropSeqToStruct( uno_Sequence *pSeq , struct Properties *pProps ) +{ + sal_Int32 i; + ProtocolProperty *pElements = (ProtocolProperty *)pSeq->elements; + for( i = 0 ; i < pSeq->nElements ; i ++ ) + { + assignFromIdlToStruct( pProps , pElements[i] ); + } +} + +void assignFromStringToStruct( const OUString & sProps , struct Properties *pProps ) +{ + uno_Sequence *pSeq = 0; + assignFromStringToPropSeq( sProps , &pSeq ); + assignFromPropSeqToStruct( pSeq , pProps ); + uno_type_destructData( &pSeq, getCppuType( (Sequence< ProtocolProperty > *)0).getTypeLibType(),0); +} + + +//---------------------------------------------------------------------------------------------- +// PropertyObject implementation +PropertyObject::PropertyObject( + struct Properties *pLocalSetting , uno_Environment *pEnvRemote, urp_BridgeImpl *pImpl ) + : m_commitChangeCondition( osl_createCondition() ) + , m_nRefCount( 0 ) + , m_pBridgeImpl( pImpl ) + , m_pLocalSetting( pLocalSetting ) + , m_pEnvRemote( pEnvRemote ) + , m_bRequestChangeHasBeenCalled( sal_False ) + , m_bServerWaitingForCommit( sal_False ) + , m_bApplyProperties( sal_False ) +{ + acquire = staticAcquire; + release = staticRelease; + pDispatcher = staticDispatch; +} + +PropertyObject::~PropertyObject() +{ + osl_destroyCondition( m_commitChangeCondition ); +} + +void SAL_CALL PropertyObject::thisDispatch( + typelib_TypeDescription const * pMemberType, void * pReturn, void * ppArgs[], + uno_Any ** ppException ) +{ + OSL_ASSERT( pMemberType->eTypeClass == typelib_TypeClass_INTERFACE_METHOD ); + + typelib_InterfaceMethodTypeDescription *pMethodType = + ( typelib_InterfaceMethodTypeDescription * ) pMemberType; + + switch( pMethodType->aBase.nPosition ) + { + case METHOD_QUERY_INTERFACE: + OSL_ENSURE( 0 , "not implemented yet !" ); + break; + case METHOD_GET_PROPERTIES: + { + implGetProperties( (uno_Sequence **) pReturn ); + *ppException = 0; + break; + } + case METHOD_COMMIT_CHANGE: + { + implCommitChange( *(uno_Sequence ** ) ppArgs[0] , ppException ); + break; + } + case METHOD_REQUEST_CHANGE: + { + *(sal_Int32 *) pReturn = implRequestChange( *(sal_Int32 *)ppArgs[0], ppException ); + break; + } + default: + OSL_ENSURE( 0 , "unkown method !" ); + } +} + +void SAL_CALL PropertyObject::localGetPropertiesFromRemote( struct Properties *pR ) +{ + OUString oid = OUString::createFromAscii( g_NameOfUrpProtocolPropertiesObject ); + + typelib_TypeDescription *pInterfaceType = 0; + getCppuType( (Reference< XProtocolProperties > *) 0 ).getDescription( &pInterfaceType ); + + if( !pInterfaceType->bComplete ) + { + typelib_typedescription_complete( &pInterfaceType ); + } + + typelib_TypeDescription *pMethodType = 0; + typelib_typedescriptionreference_getDescription( + &pMethodType, + ((typelib_InterfaceTypeDescription*) pInterfaceType)->ppAllMembers[METHOD_GET_PROPERTIES] ); + + + uno_Sequence *pResult = 0; + uno_Any exception; + uno_Any *pException = &exception; + urp_sendRequest( m_pEnvRemote, + pMethodType, + oid.pData, + (typelib_InterfaceTypeDescription*) pInterfaceType, + &pResult, + 0, + &pException ); + + if( pException ) + { + OSL_ENSURE( 0 , "remote urp-bridge doesn't support property-object" ); + uno_any_destruct( pException , 0 ); + return; + } + + ProtocolProperty *pP = (ProtocolProperty * ) pResult->elements; + for( sal_Int32 i = 0; i < pResult->nElements ; i ++ ) + { + if( ! assignFromIdlToStruct( pR , pP[i] ) ) + { + OSL_ENSURE( 0 , "unknown property !!!!" ); + } + } + + typelib_typedescription_release( pInterfaceType ); + typelib_typedescription_release( pMethodType ); +} + + +// implementation for call from remote +void SAL_CALL PropertyObject::implGetProperties( uno_Sequence **ppReturnValue ) +{ + typelib_TypeDescription *pElementType= 0; + getCppuType( (Sequence< ProtocolProperty > *)0).getDescription( &pElementType ); + + OSL_ENSURE( pElementType , "Couldn't get property type" ); + + *ppReturnValue = 0; + uno_sequence_construct( ppReturnValue , pElementType , 0, MAX_PROPERTIES , 0 ); + ProtocolProperty *pElements = (ProtocolProperty * ) ( *ppReturnValue )->elements; + Properties *pP = m_pLocalSetting; + + assignToIdl( &(pElements[PROPERTY_BRIDGEID]),PROPERTY_BRIDGEID, *(Sequence< sal_Int8 > *)&(pP->seqBridgeID) ); + assignToIdl( &(pElements[PROPERTY_TYPECACHESIZE]),PROPERTY_TYPECACHESIZE,pP->nTypeCacheSize ); + assignToIdl( &(pElements[PROPERTY_OIDCACHESIZE]),PROPERTY_OIDCACHESIZE, pP->nOidCacheSize ); + assignToIdl( &(pElements[PROPERTY_TIDCACHESIZE]),PROPERTY_TIDCACHESIZE, pP->nTidCacheSize ); + assignToIdl( &(pElements[PROPERTY_SUPPORTEDVERSIONS]),PROPERTY_SUPPORTEDVERSIONS, pP->sSupportedVersions ); + assignToIdl( &(pElements[PROPERTY_VERSION]),PROPERTY_VERSION, pP->sVersion ); + assignToIdl( &(pElements[PROPERTY_FLUSHBLOCKSIZE]), PROPERTY_FLUSHBLOCKSIZE,pP->nFlushBlockSize ); + assignToIdl( &(pElements[PROPERTY_ONEWAYTIMEOUT_MUSEC]), PROPERTY_ONEWAYTIMEOUT_MUSEC, pP->nOnewayTimeoutMUSEC ); + assignToIdl( &(pElements[PROPERTY_SUPPORTSMUSTREPLY]), PROPERTY_SUPPORTSMUSTREPLY, pP->bSupportsMustReply ); + assignToIdl( &(pElements[PROPERTY_SUPPERTSSYNCHRONOUS]), PROPERTY_SUPPERTSSYNCHRONOUS, pP->bSupportsSynchronous ); + assignToIdl( &(pElements[PROPERTY_SUPPORTSMULTIPLESYNCHRONOUS]), PROPERTY_SUPPORTSMULTIPLESYNCHRONOUS, pP->bSupportsMultipleSynchronous ); + assignToIdl( &(pElements[PROPERTY_CLEARCACHE]), PROPERTY_CLEARCACHE, pP->bClearCache ); + + typelib_typedescription_release( pElementType ); +} + +//---------------------------------------------------------------------------------------------- +sal_Int32 SAL_CALL PropertyObject::localRequestChange( ) +{ + sal_Int32 nResult = 0; + sal_Bool bCall = sal_True; + + // disallow marshaling NOW ! + ClearableMutexGuard marshalingGuard( m_pBridgeImpl->m_marshalingMutex ); + { + MutexGuard guard( m_mutex ); + if( m_bRequestChangeHasBeenCalled || m_bServerWaitingForCommit ) + { + // another transaction is already underway + // try again later ! + bCall = sal_False; + } + m_bRequestChangeHasBeenCalled = sal_True; + + if( bCall ) + { + // calulate random number + rtlRandomPool pool = rtl_random_createPool (); + rtl_random_getBytes( pool , &m_nRandomNumberOfRequest, sizeof( m_nRandomNumberOfRequest ) ); + rtl_random_destroyPool( pool ); + } + } + + if( bCall ) + { + OUString oid = OUString::createFromAscii( g_NameOfUrpProtocolPropertiesObject ); + + // gather types for calling + typelib_TypeDescription *pInterfaceType = 0; + getCppuType( (Reference< XProtocolProperties > *) 0 ).getDescription( &pInterfaceType ); + + if( !pInterfaceType->bComplete ) + { + typelib_typedescription_complete( &pInterfaceType ); + } + + typelib_TypeDescription *pMethodType = 0; + typelib_typedescriptionreference_getDescription( + &pMethodType, + ((typelib_InterfaceTypeDescription*) pInterfaceType)->ppAllMembers[METHOD_REQUEST_CHANGE] ); + + void *pArg1 = &m_nRandomNumberOfRequest; + void **ppArgs = &pArg1; + + uno_Any exception; + uno_Any *pException = &exception; + + ClientJob job( m_pEnvRemote, + 0, + m_pBridgeImpl, + oid.pData, + pMethodType, + (typelib_InterfaceTypeDescription*) pInterfaceType, + &nResult, + ppArgs, + &pException ); + + // put the call on the line ! + sal_Bool bSuccess = job.pack(); + + // now allow writing on wire again. + // NOTE : this has been locked, because it is inevitable to set m_bRequestChangeHasBeenCalled + // and call requestChange in an atomar operation. Otherwise, implRequestChange may be called + // inbetween and reply, before the request is put on the wire. This certainly would + // be confusing for the remote counterpart ! + marshalingGuard.clear(); + + // wait for the reply ... + if( bSuccess ) + { + job.wait(); + + if( pException ) + { + // the object is unknown on the other side. + uno_any_destruct( pException , 0 ); + nResult = 0; + } + } + else + { + nResult = 0; + } + typelib_typedescription_release( pInterfaceType ); + typelib_typedescription_release( pMethodType ); + } + + { + MutexGuard guard( m_mutex ); + m_bRequestChangeHasBeenCalled = sal_False; + m_bServerWaitingForCommit = ( 0 == nResult ); + } + return nResult; +} + +// implementation for call from remote +sal_Int32 SAL_CALL PropertyObject::implRequestChange( sal_Int32 nRandomNumber, uno_Any **ppException ) +{ + sal_Int32 nResult = 0; + MutexGuard guard( m_mutex ); + if( m_bRequestChangeHasBeenCalled ) + { + // this side has also called requestChange, now negotiate, which side is allowed + // to commit the change ! + if( m_nRandomNumberOfRequest > nRandomNumber ) + { + // this side may commit !!!! + nResult = 0; + } + else if( m_nRandomNumberOfRequest == nRandomNumber ) + { + // sorry, try again ! + nResult = -1; + } + else if( m_nRandomNumberOfRequest < nRandomNumber ) + { + // the other side may commit ! + nResult = 1; + // m_bServerWaitingForCommit will be set by localRequestChange + } + } + else + { + // This side has NOT called requestChange, so the other side may commit + nResult = 1; + m_bServerWaitingForCommit = sal_True; + } + + *ppException = 0; + return nResult; +} + + + +void SAL_CALL PropertyObject::localCommitChange( const ::rtl::OUString &sProps , sal_Bool *pbExceptionThrown ) +{ + // lock the bridge NOW ! + // NOTE: it is not allowed for other threads to call, when a commit change is underway. + // The remote counterpart cannot if the call following the commit already uses + // the new properties or not. + MutexGuard guard( m_pBridgeImpl->m_marshalingMutex ); + + OUString oid = OUString::createFromAscii( g_NameOfUrpProtocolPropertiesObject ); + + osl_resetCondition( m_commitChangeCondition ); + + Properties props = *m_pLocalSetting; + + typelib_TypeDescription *pInterfaceType = 0; + getCppuType( (Reference< XProtocolProperties > *) 0 ).getDescription( &pInterfaceType ); + + if( !pInterfaceType->bComplete ) + { + typelib_typedescription_complete( &pInterfaceType ); + } + + typelib_TypeDescription *pMethodType = 0; + typelib_typedescriptionreference_getDescription( + &pMethodType, + ((typelib_InterfaceTypeDescription*) pInterfaceType)->ppAllMembers[METHOD_COMMIT_CHANGE] ); + +// typelib_TypeDescription *pSequenceType= 0; + + + // extract name/value pairs + uno_Sequence *pSeq = 0; + assignFromStringToPropSeq( sProps, &pSeq ); + assignFromPropSeqToStruct( pSeq , &props ); +// ::std::list< OUString > lst; +// extractTokens( sProps , lst ); + +// getCppuType( (Sequence< ProtocolProperty > *)0).getDescription( &pSequenceType ); +// uno_sequence_construct( &pSeq , pSequenceType , 0, lst.size() , 0 ); +// ProtocolProperty *pElements = (ProtocolProperty * ) pSeq->elements; + +// sal_Int32 i = 0; +// for( ::std::list< OUString >::iterator ii = lst.begin() ; ii != lst.end() ; ++ ii, i++ ) +// { +// sal_Int32 nAssign = (*ii).indexOf( '=' ); +// if( -1 == nAssign ) +// { +// OString o = OUStringToOString( *ii, RTL_TEXTENCODING_ASCII_US ); +// OSL_ENSURE( !"wrong protocol propertyt format, ignored", o.getStr() ); +// } +// OUString sPropName = (*ii).copy( 0, nAssign ); +// OUString sValue = (*ii).copy( nAssign +1, (*ii).getLength() - nAssign -1 ); + +// sal_Int32 nIndex = getIndexFromString( sPropName ); +// if( -1 == nIndex ) +// { +// OString o = OUStringToOString( sPropName , RTL_TEXTENCODING_ASCII_US); +// OSL_ENSURE( !"unknown protocol property, ignored", o.getStr() ); +// } +// switch( nIndex ) +// { +// // bools +// case PROPERTY_CLEARCACHE: +// { +// sal_Bool bClearCache = (sal_Bool ) sValue.toInt32(); +// assignToIdl( &(pElements[i]) , nIndex , bClearCache ); +// break; +// } +// // ints +// case PROPERTY_TYPECACHESIZE: +// case PROPERTY_OIDCACHESIZE: +// case PROPERTY_TIDCACHESIZE: +// case PROPERTY_FLUSHBLOCKSIZE: +// case PROPERTY_ONEWAYTIMEOUT_MUSEC: +// { +// sal_Int32 nValue = sValue.toInt32(); +// assignToIdl( &(pElements[i]) , nIndex , nValue ); +// break; +// } + +// // strings +// case PROPERTY_VERSION: +// assignToIdl( &(pElements[i]) , nIndex , sValue ); +// break; +// default: +// OString o = OUStringToOString( sPropName, RTL_TEXTENCODING_ASCII_US ); +// OSL_ENSURE( !"readonly protocol property, ignored" , o.getStr() ); +// } +// assignFromIdlToStruct( &props, pElements[i] ); +// } + + void *pArg1 = &pSeq; + uno_Any exception; + uno_Any *pException = &exception; + + ClientJob job( m_pEnvRemote, + 0, + m_pBridgeImpl, + oid.pData, + pMethodType, + (typelib_InterfaceTypeDescription*) pInterfaceType, + 0, + &pArg1, + &pException ); + job.setBridgePropertyCall(); + if( job.pack() ) + { + job.wait(); + } + else + { + OSL_ASSERT( pException != NULL ); + } + + ::uno_type_destructData( + &pSeq, getCppuType( (Sequence< ProtocolProperty > *)0).getTypeLibType(), 0 ); + + *pbExceptionThrown = pException ? sal_True : sal_False; + + if( pException ) + { + OString o = OUStringToOString( ((com::sun::star::uno::Exception*)pException->pData)->Message, + RTL_TEXTENCODING_ASCII_US); + OSL_ENSURE( !"exception thrown during calling on PropertyObject",o.getStr() ); + uno_any_destruct( pException , 0 ); + } + else + { + m_pBridgeImpl->applyProtocolChanges( props ); + m_bServerWaitingForCommit = sal_False; + m_bApplyProperties = sal_False; + } + + // let the reader thread go ... + osl_setCondition( m_commitChangeCondition ); + + typelib_typedescription_release( pMethodType ); + typelib_typedescription_release( pInterfaceType ); +} + +void SAL_CALL PropertyObject::implCommitChange( uno_Sequence *pSequence, uno_Any **ppException ) +{ + MutexGuard guard( m_mutex ); + m_propsToBeApplied = *m_pLocalSetting; + + ProtocolProperty *pP = (ProtocolProperty * ) pSequence->elements; + for( sal_Int32 i = 0; i < pSequence->nElements ; i ++ ) + { + if( ! assignFromIdlToStruct( &m_propsToBeApplied , pP[i] ) ) + { + InvalidProtocolChangeException exception; + Type type = getCppuType( &exception ); + exception.Message = OUString::createFromAscii( "urp: unknown Property " ); + exception.Message += pP[i].Name; + exception.invalidProperty = pP[i]; + exception.reason = 1; + + uno_type_any_construct( *ppException, &exception, type.getTypeLibType() , 0 ); + + m_bApplyProperties = sal_False; + m_bServerWaitingForCommit = sal_False; + return; + } + } + + m_bApplyProperties = sal_True; + *ppException = 0; +} + +Properties SAL_CALL PropertyObject::getCommitedChanges() +{ + MutexGuard guard( m_mutex ); + OSL_ASSERT( m_bApplyProperties ); + m_bApplyProperties = sal_False; + m_bServerWaitingForCommit = sal_False; + return m_propsToBeApplied; +} + +void SAL_CALL PropertyObject::waitUntilChangesAreCommitted() +{ + osl_waitCondition( m_commitChangeCondition , 0 ); +} +} diff --git a/bridges/source/remote/urp/urp_propertyobject.hxx b/bridges/source/remote/urp/urp_propertyobject.hxx new file mode 100644 index 000000000000..3b6bd1824e27 --- /dev/null +++ b/bridges/source/remote/urp/urp_propertyobject.hxx @@ -0,0 +1,108 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <stdio.h> +#include <osl/interlck.h> +#include <osl/mutex.hxx> + +#ifndef _OSL_CONDITN_H_ +#include <osl/conditn.h> +#endif +#include <rtl/string.hxx> +#include <uno/sequence2.h> + +#ifndef _BRIDGES_REMOTE_REMOTE_H_ +#include <bridges/remote/remote.h> +#endif +#include "urp_property.hxx" + +namespace bridges_urp { + +struct urp_BridgeImpl; +const sal_Char g_NameOfUrpProtocolPropertiesObject[] = "UrpProtocolProperties"; + +// helper functions +void assignFromStringToStruct( const ::rtl::OUString & sProps , struct Properties *pProps ); + +class PropertyObject : public remote_Interface +{ +private: + ::osl::Mutex m_mutex; + oslCondition m_commitChangeCondition; + oslInterlockedCount m_nRefCount; + urp_BridgeImpl *m_pBridgeImpl; + struct Properties *m_pLocalSetting; + struct Properties m_propsToBeApplied; + + uno_Environment *m_pEnvRemote; + sal_Int32 m_nRandomNumberOfRequest; + sal_Bool m_bRequestChangeHasBeenCalled; + sal_Bool m_bServerWaitingForCommit; + sal_Bool m_bApplyProperties; + +public: + PropertyObject( + struct Properties *pLocalSetting , uno_Environment *pEnvRemote, urp_BridgeImpl *pImpl ); + ~PropertyObject(); + + void SAL_CALL thisAcquire( ) + { + osl_incrementInterlockedCount( &m_nRefCount ); + } + + void SAL_CALL thisRelease() + { + if( ! osl_decrementInterlockedCount( &m_nRefCount ) ) + { + delete this; + } + } + + void SAL_CALL thisDispatch( typelib_TypeDescription const * pMemberType, + void * pReturn, + void * pArgs[], + uno_Any ** ppException ); + +public: // local + sal_Int32 SAL_CALL localRequestChange( ); + void SAL_CALL localCommitChange( const ::rtl::OUString &properties, sal_Bool *pbExceptionThrown ); + void SAL_CALL localGetPropertiesFromRemote( struct Properties * ); + + // returns 0, if nothing was commited. + inline sal_Bool SAL_CALL changesHaveBeenCommited() + { return m_bApplyProperties; } + Properties SAL_CALL getCommitedChanges(); + + void SAL_CALL waitUntilChangesAreCommitted(); + +protected: + // these methods are called by thisDispatch + void SAL_CALL implGetProperties( uno_Sequence **ppReturnValue ); + sal_Int32 SAL_CALL implRequestChange( sal_Int32 nRandomNumber, uno_Any **ppException ); + void SAL_CALL implCommitChange( uno_Sequence *seqOfProperties, uno_Any **ppException ); +}; + +} diff --git a/bridges/source/remote/urp/urp_reader.cxx b/bridges/source/remote/urp/urp_reader.cxx new file mode 100644 index 000000000000..fda6c5e322eb --- /dev/null +++ b/bridges/source/remote/urp/urp_reader.cxx @@ -0,0 +1,832 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <string.h> + +#include <osl/diagnose.h> +#include <rtl/ustrbuf.hxx> + +#include <bridges/remote/connection.h> +#include <bridges/remote/counter.hxx> +#include <bridges/remote/context.h> +#include <bridges/remote/helper.hxx> + +#include <com/sun/star/uno/XCurrentContext.hpp> +#include <uno/environment.h> + +#include "urp_reader.hxx" +#include "urp_writer.hxx" +#include "urp_dispatch.hxx" +#include "urp_job.hxx" +#include "urp_bridgeimpl.hxx" +#include "urp_log.hxx" +#include "urp_propertyobject.hxx" + +using namespace ::rtl; +using namespace ::osl; +using namespace ::com::sun::star::uno; + +#if OSL_DEBUG_LEVEL > 1 +static MyCounter thisCounter( "DEBUG : ReaderThread" ); +#endif + +namespace bridges_urp +{ + + /** + * This callback is used to ensure, that the release call is sent for the correct type. + * + ***/ + void SAL_CALL urp_releaseRemoteCallback ( + remote_Interface *, rtl_uString *pOid, + typelib_TypeDescriptionReference *pTypeRef, uno_Environment *pEnvRemote ) + { + remote_Context *pContext = (remote_Context *) pEnvRemote->pContext; + urp_BridgeImpl *pImpl = (urp_BridgeImpl*) ( pContext->m_pBridgeImpl ); + + pImpl->m_pWriter->insertReleaseRemoteCall( pOid , pTypeRef ); + } + + + struct MessageFlags + { + sal_uInt16 nMethodId; + sal_Bool bRequest; + sal_Bool bType; + sal_Bool bOid; + sal_Bool bTid; + sal_Bool bException; + sal_Bool bMustReply; + sal_Bool bSynchronous; + sal_Bool bMoreFlags; + sal_Bool bIgnoreCache; + sal_Bool bBridgePropertyCall; + ///-------------------------- + inline MessageFlags() + { + bTid = sal_False; + bOid = sal_False; + bType = sal_False; + bException = sal_False; + bMoreFlags = sal_False; + bIgnoreCache = sal_False; + bBridgePropertyCall = sal_False; + } + //--------------------------- + }; // end struct MessageFlags + +inline sal_Bool OReaderThread::getMemberTypeDescription( + typelib_InterfaceAttributeTypeDescription **ppAttributeType, + typelib_InterfaceMethodTypeDescription **ppMethodType, + sal_Bool *pbIsSetter, + sal_uInt16 nMethodId , + typelib_TypeDescriptionReference * pITypeRef ) +{ + if( pITypeRef->eTypeClass != typelib_TypeClass_INTERFACE ) + { + OUStringBuffer sMessage; + sMessage.appendAscii( "interface type is not of typeclass interface (" ); + sMessage.append( (sal_Int32) pITypeRef->eTypeClass ); + m_pBridgeImpl->addError( sMessage.makeStringAndClear() ); + OSL_ENSURE( 0 , "type is not an interface" ); + return sal_False; + } + + typelib_InterfaceTypeDescription *pInterfaceType = 0; + TYPELIB_DANGER_GET( + (typelib_TypeDescription **)&pInterfaceType , pITypeRef ); + if( ! pInterfaceType ) + { + OUStringBuffer sMessage; + sMessage.appendAscii( "No typedescription can be retrieved for type " ); + sMessage.append( OUString( pITypeRef->pTypeName ) ); + m_pBridgeImpl->addError( sMessage.makeStringAndClear() ); + OSL_ENSURE( 0 , "urp: unknown type " ); + return sal_False; + } + + if( ! pInterfaceType->aBase.bComplete ) + { + typelib_typedescription_complete( (typelib_TypeDescription **) &pInterfaceType ); + } + + if ( nMethodId >= pInterfaceType->nMapFunctionIndexToMemberIndex ) + { + OUStringBuffer sMessage; + sMessage.appendAscii( "vtable out of range for type " ); + sMessage.append( OUString( pITypeRef->pTypeName ) ); + sMessage.appendAscii( " (" ); + sMessage.append( (sal_Int32) nMethodId ); + sMessage.appendAscii( " )" ); + m_pBridgeImpl->addError( sMessage.makeStringAndClear() ); + + OSL_ENSURE( 0 , "vtable index out of range" ); + return sal_False; + } + + sal_Int32 nMemberIndex = pInterfaceType->pMapFunctionIndexToMemberIndex[ nMethodId ]; + + if( !( pInterfaceType->nAllMembers > nMemberIndex && nMemberIndex >= 0 ) ) + { + OUStringBuffer sMessage; + sMessage.appendAscii( "vtable out of range for type " ); + sMessage.append( OUString( pITypeRef->pTypeName ) ); + sMessage.appendAscii( " (" ); + sMessage.append( (sal_Int32) nMethodId ); + sMessage.appendAscii( " )" ); + m_pBridgeImpl->addError( sMessage.makeStringAndClear() ); + + OSL_ENSURE( 0 , "vtable index out of range" ); + return sal_False; + } + + typelib_InterfaceMemberTypeDescription *pMemberType = 0; + typelib_typedescriptionreference_getDescription( + (typelib_TypeDescription **) &pMemberType,pInterfaceType->ppAllMembers[nMemberIndex]); + + if(! pMemberType ) + { + OUStringBuffer sMessage; + sMessage.appendAscii( "unknown method type description for type" ); + sMessage.append( OUString( pITypeRef->pTypeName ) ); + sMessage.appendAscii( " (" ); + sMessage.append( (sal_Int32) nMethodId ); + sMessage.appendAscii( " )" ); + m_pBridgeImpl->addError( sMessage.makeStringAndClear() ); + + OSL_ENSURE( 0 , "unknown method type description" ); + return sal_False; + } + + if( typelib_TypeClass_INTERFACE_ATTRIBUTE == pMemberType->aBase.eTypeClass ) + { + // Note: pMapMemberIndexToFunctionIndex always contains the function + // index of the attribute getter! setter function index is getter index + // + 1. + *ppAttributeType = (typelib_InterfaceAttributeTypeDescription *) pMemberType; + *pbIsSetter = ! ( + pInterfaceType->pMapMemberIndexToFunctionIndex[nMemberIndex] == nMethodId ); + } + else + { + *ppMethodType = (typelib_InterfaceMethodTypeDescription *) pMemberType; + } + + TYPELIB_DANGER_RELEASE( (typelib_TypeDescription * )pInterfaceType ); + return sal_True; +} + +OReaderThread::OReaderThread( remote_Connection *pConnection, + uno_Environment *pEnvRemote, + OWriterThread * pWriterThread ) : + m_pConnection( pConnection ), + m_pEnvRemote( pEnvRemote ), + m_pWriterThread( pWriterThread ), + m_bDestroyMyself( sal_False ), + m_bContinue( sal_True ), + m_pBridgeImpl((struct urp_BridgeImpl*) + ((remote_Context *)pEnvRemote->pContext)->m_pBridgeImpl ), + m_unmarshal( m_pBridgeImpl, m_pEnvRemote, ::bridges_remote::remote_createStub ) +{ + m_pEnvRemote->acquireWeak( m_pEnvRemote ); + m_pConnection->acquire( m_pConnection ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.acquire(); +#endif +} + + +OReaderThread::~OReaderThread( ) +{ + m_pEnvRemote->releaseWeak( m_pEnvRemote ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.release(); +#endif +} + +// may only be called in the callstack of this thread !!!!! +// run() -> dispose() -> destroyYourself() +void OReaderThread::destroyYourself() +{ + m_bDestroyMyself = sal_True; + m_pConnection->release( m_pConnection ); + m_pConnection = 0; + m_bContinue = sal_False; +} + +void OReaderThread::onTerminated() +{ + if( m_bDestroyMyself ) + { + delete this; + } +} + + +void OReaderThread::disposeEnvironment() +{ + struct remote_Context *pContext = + ( struct remote_Context * ) m_pEnvRemote->pContext; + m_bContinue = sal_False; + if( ! pContext->m_pBridgeImpl->m_bDisposed ) + { + uno_Environment *pEnvRemote = 0; + m_pEnvRemote->harden( &pEnvRemote , m_pEnvRemote ); + if( pEnvRemote ) + { + pEnvRemote->dispose( m_pEnvRemote ); + pEnvRemote->release( m_pEnvRemote ); + } + else + { + // environment has been disposed eitherway ! + } + } +} + +inline sal_Bool OReaderThread::readBlock( sal_Int32 *pnMessageCount ) +{ + m_unmarshal.setSize( 8 ); + if( 8 != m_pConnection->read( m_pConnection , m_unmarshal.getBuffer(), 8 ) ) + { + OUString s( RTL_CONSTASCII_USTRINGPARAM( "Unexpected connection closure" ) ); + m_pBridgeImpl->addError( s ); + return sal_False; + } + + sal_Int32 nSize; + m_unmarshal.unpackInt32( &nSize ); + m_unmarshal.unpackInt32( pnMessageCount ); + + if( nSize < 0 ) + { + // buffer too big + // no exception can be thrown, because there is no thread id, which could be + // used. -> terminate ! + OUStringBuffer s; + s.appendAscii( "Packet-size too big (" ); + s.append( (sal_Int64) (sal_uInt32 ) nSize ); + s.append( sal_Unicode( ')' ) ); + m_pBridgeImpl->addError( s.makeStringAndClear() ); + OSL_ENSURE( 0 , "urp bridge: Packet-size too big" ); + return sal_False; + } + + if( 0 == nSize ) + { + // normal termination ! + return sal_False; + } + + // allocate the necessary memory + if( ! m_unmarshal.setSize( nSize ) ) + { + OUStringBuffer s; + s.appendAscii( "Packet-size too big, couln't allocate necessary memory (" ); + s.append( (sal_Int64) (sal_uInt32 ) nSize ); + s.append( sal_Unicode( ')' ) ); + m_pBridgeImpl->addError( s.makeStringAndClear() ); + OSL_ENSURE( 0 , "urp bridge: messages size too large, terminating connection" ); + return sal_False; + } + + sal_Int32 nRead = m_pConnection->read( m_pConnection , m_unmarshal.getBuffer() , nSize ); + + if( nSize != nRead ) + { + OUStringBuffer s; + s.appendAscii( "Unexpected connection closure, inconsistent packet (" ); + s.append( (sal_Int64) (sal_uInt32 ) nSize ); + s.appendAscii( " asked, " ); + s.append( (sal_Int64) (sal_uInt32 ) nRead ); + s.appendAscii( " got )" ); + m_pBridgeImpl->addError( s.makeStringAndClear() ); + // couldn't get the asked amount of bytes, quit + // should only occur, when the environment has already been disposed + OSL_ENSURE( m_pBridgeImpl->m_bDisposed , "urp bridge: inconsistent packet, terminating connection." ); + return sal_False; + } + return sal_True; +} + +inline sal_Bool OReaderThread::readFlags( struct MessageFlags *pFlags ) +{ + sal_uInt8 nBitField; + if( ! m_unmarshal.unpackInt8( &nBitField ) ) + { + m_pBridgeImpl->addError( "Unexpected end of message header (1)" ); + return sal_False; + } + + if( HDRFLAG_LONGHEADER & nBitField ) + { + // this is a long header, interpret the byte as bitfield + pFlags->bTid = (HDRFLAG_NEWTID & nBitField ); + pFlags->bRequest = (HDRFLAG_REQUEST & nBitField); + + if( pFlags->bRequest ) + { + // request + pFlags->bType = ( HDRFLAG_NEWTYPE & nBitField ); + pFlags->bOid = ( HDRFLAG_NEWOID & nBitField ); + pFlags->bIgnoreCache = ( HDRFLAG_IGNORECACHE & nBitField ); + pFlags->bMoreFlags = ( HDRFLAG_MOREFLAGS & nBitField ); + + if( pFlags->bMoreFlags ) + { + // another byte with flags + sal_Int8 moreFlags; + if( ! m_unmarshal.unpackInt8( &moreFlags ) ) + { + m_pBridgeImpl->addError( "Unexpected end of message header (2)" ); + return sal_False; + } + pFlags->bSynchronous = ( HDRFLAG_SYNCHRONOUS & moreFlags ); + pFlags->bMustReply = ( HDRFLAG_MUSTREPLY & moreFlags ); + OSL_ENSURE( (pFlags->bSynchronous && pFlags->bMustReply) || + (!pFlags->bSynchronous && !pFlags->bMustReply), + "urp-bridge : customized calls currently not supported !"); + } + + if( HDRFLAG_LONGMETHODID & nBitField ) + { + // methodid as unsigned short + if( ! m_unmarshal.unpackInt16( &(pFlags->nMethodId )) ) + { + m_pBridgeImpl->addError( "Unexpected end of message header (3)" ); + return sal_False; + } + } + else + { + sal_uInt8 id; + if( ! m_unmarshal.unpackInt8( &id ) ) + { + m_pBridgeImpl->addError( "Unexpected end of message header (4)" ); + return sal_False; + } + pFlags->nMethodId = (sal_uInt16) id; + } + } + else + { + // reply + pFlags->bRequest = sal_False; + pFlags->bException = ( HDRFLAG_EXCEPTION & nBitField ); + } + } + else + { + // short request + pFlags->bRequest = sal_True; + if( 0x40 & nBitField ) + { + sal_uInt8 lower; + if( ! m_unmarshal.unpackInt8( &lower ) ) + { + m_pBridgeImpl->addError( "Unexpected end of message header (5)" ); + return sal_False; + } + pFlags->nMethodId = ( nBitField & 0x3f ) << 8 | lower; + } + else + { + pFlags->nMethodId = ( nBitField & 0x3f ); + } + } + return sal_True; +} + +void OReaderThread::run() +{ + // This vars are needed to hold oid,tid and type information, which should not be cached. + Type lastTypeNoCache; + OUString lastOidNoCache; + ByteSequence lastTidNoCache; + + while( m_bContinue ) + { + sal_Int32 nMessageCount; + if( ! readBlock( &nMessageCount ) ) + { + disposeEnvironment(); + break; + } + + uno_Environment *pEnvRemote = 0; + m_pEnvRemote->harden( &pEnvRemote , m_pEnvRemote ); + if( !pEnvRemote ) + { + // environment has been disposed already, quit here + break; + } + ServerMultiJob *pMultiJob = 0; + remote_Interface *pLastRemoteI = 0; + while( ! m_unmarshal.finished() ) + { +#ifdef BRIDGES_URP_PROT + sal_uInt32 nLogStart = m_unmarshal.getPos(); + sal_Bool bIsOneWay = sal_False; + OUString sMemberName; +#endif + MessageFlags flags; + + if( ! readFlags( &flags ) ) + { + m_pBridgeImpl->addError( "incomplete message, skipping block" ); + OSL_ENSURE ( 0 , "urp-bridge : incomplete message, skipping block" ); + break; + } + + // use these ** to access the ids fast ( avoid acquire/release calls ) + sal_Sequence **ppLastTid = flags.bIgnoreCache ? + (sal_Sequence **) &lastTidNoCache : + (sal_Sequence **) &(m_pBridgeImpl->m_lastInTid); + rtl_uString **ppLastOid = flags.bIgnoreCache ? + (rtl_uString ** ) &lastOidNoCache : + (rtl_uString ** ) &(m_pBridgeImpl->m_lastInOid); + typelib_TypeDescriptionReference **ppLastType = + flags.bIgnoreCache ? + (typelib_TypeDescriptionReference ** ) &lastTypeNoCache : + (typelib_TypeDescriptionReference ** ) &(m_pBridgeImpl->m_lastInType); + + // get new type + if( flags.bType ) + { + typelib_TypeDescriptionReference *pTypeRef = 0; + if( m_unmarshal.unpackType( &pTypeRef ) ) + { + // release the old type + typelib_typedescriptionreference_release( *ppLastType ); + // set the new type + *ppLastType = pTypeRef; + + // no release on pTypeRef necessary (will be released by type dtor) + } + else + { + typelib_typedescriptionreference_release( pTypeRef ); + m_pBridgeImpl->addError( "error during unpacking (maybe cached) interface type" ); + OSL_ENSURE( 0 , "urp-bridge : error during unpacking interface type, terminating connection" ); + disposeEnvironment(); + break; + } + if( m_pBridgeImpl->m_lastInType.getTypeClass() != TypeClass_INTERFACE ) + { + OUStringBuffer sMessage; + sMessage.appendAscii( "interface type is not of typeclass interface (" ); + sMessage.append( (sal_Int32) m_pBridgeImpl->m_lastInType.getTypeClass() ); + m_pBridgeImpl->addError( sMessage.makeStringAndClear() ); + OSL_ENSURE( 0 , "urp-bridge : not an interface type" ); + disposeEnvironment(); + break; + } + } + if( flags.bOid ) + { + rtl_uString *pOid = 0; + if( m_unmarshal.unpackOid( &pOid ) ) + { + rtl_uString_release( *ppLastOid ); + *ppLastOid = pOid; + } + else + { + rtl_uString_release( pOid ); + m_pBridgeImpl->addError( "error during unpacking (maybe cached) oid" ); + OSL_ENSURE( 0 , "urp-bridge : error during unpacking cached data, terminating connection" ); + disposeEnvironment(); + break; + } + } + + if( flags.bTid ) + { + sal_Sequence *pSeq = 0; + if( m_unmarshal.unpackTid( &pSeq ) ) + { + rtl_byte_sequence_release( *ppLastTid ); + *ppLastTid = pSeq; + } + else + { + rtl_byte_sequence_release( pSeq ); + + m_pBridgeImpl->addError( "error during unpacking (maybe cached) tid" ); + OSL_ENSURE( 0 , "urp-bridge : error during unpacking cached data, terminating connection" ); + disposeEnvironment(); + break; + } + } + + // do the job + if( flags.bRequest ) + { + bool bHasCc = m_pBridgeImpl->m_properties.bCurrentContext + && flags.nMethodId != REMOTE_RELEASE_METHOD_INDEX + && !rtl::OUString( *ppLastOid ).equalsAsciiL( + RTL_CONSTASCII_STRINGPARAM( + g_NameOfUrpProtocolPropertiesObject ) ); + remote_Interface * pCc = 0; + if ( bHasCc ) + { + typelib_TypeDescription * pType = 0; + TYPELIB_DANGER_GET( + &pType, + XCurrentContext::static_type().getTypeLibType() ); + bool ok = m_unmarshal.unpack( &pCc, pType ); + TYPELIB_DANGER_RELEASE( pType ); + if ( !ok ) + { + OSL_ENSURE( + false, + ("urp_bridge: error while unpacking current" + " context") ); + disposeEnvironment(); + break; + } + } + + //-------------------------- + // handle request + //-------------------------- + // get the membertypedescription + typelib_InterfaceMethodTypeDescription *pMethodType = 0; + typelib_InterfaceAttributeTypeDescription *pAttributeType = 0; + sal_Bool bIsSetter = sal_False; + + if( getMemberTypeDescription( + &pAttributeType, &pMethodType, &bIsSetter, + flags.nMethodId, *ppLastType ) ) + { + if( ! pLastRemoteI || flags.bOid || flags.bType ) + { + // a new interface must be retrieved + + // retrieve the interface NOW from the environment + // (avoid race conditions : oneway followed by release ) + typelib_InterfaceTypeDescription *pInterfaceType = 0; + + TYPELIB_DANGER_GET( + (typelib_TypeDescription ** ) &pInterfaceType , + *ppLastType ); + if( !pInterfaceType ) + { + OUStringBuffer sMessage; + sMessage.appendAscii( "Couldn't retrieve type description for type " ); + sMessage.append( OUString( (*ppLastType)->pTypeName ) ); + m_pBridgeImpl->addError( sMessage.makeStringAndClear() ); + delete pMultiJob; + pMultiJob = 0; + disposeEnvironment(); + pLastRemoteI = 0; // stubs are released during dispose eitherway + break; + } + pEnvRemote->pExtEnv->getRegisteredInterface( + pEnvRemote->pExtEnv, ( void ** ) &pLastRemoteI, + *ppLastOid, pInterfaceType ); + TYPELIB_DANGER_RELEASE( (typelib_TypeDescription * )pInterfaceType ); + + if( !pLastRemoteI && + REMOTE_RELEASE_METHOD_INDEX != flags.nMethodId && + 0 == rtl_ustr_ascii_compare_WithLength( + (*ppLastOid)->buffer, (*ppLastOid)->length, g_NameOfUrpProtocolPropertiesObject ) ) + { + // check for bridge internal propertyobject + pLastRemoteI = m_pBridgeImpl->m_pPropertyObject; + pLastRemoteI->acquire( pLastRemoteI ); + flags.bBridgePropertyCall = sal_True; + } + + // NOTE : Instance provider is called in the executing thread + // Otherwise, instance provider may block the bridge + } + + sal_Bool bCallIsOneway = sal_False; + if( flags.bMoreFlags ) + { + // flags override the default ! + bCallIsOneway = ! flags.bSynchronous; + } + else if( pMethodType && pMethodType->bOneWay ) + { + bCallIsOneway = sal_True; + } + + if( pMultiJob && ! flags.bTid && bCallIsOneway && ! pMultiJob->isFull()) + { + // add to the existing multijob, nothing to do here + } + else + { + // create a new multijob + if( pMultiJob ) + { + // there exists an old one, start it first. + pMultiJob->initiate(); + } + + pMultiJob = new ServerMultiJob( + pEnvRemote, + static_cast< remote_Context * >( + pEnvRemote->pContext ), + *ppLastTid, m_pBridgeImpl, &m_unmarshal, + nMessageCount ); + } + + pMultiJob->setCurrentContext( bHasCc, pCc ); + pMultiJob->setIgnoreCache( flags.bIgnoreCache ); + pMultiJob->setType( *ppLastType ); + if( pMethodType ) + { + pMultiJob->setMethodType( pMethodType , + REMOTE_RELEASE_METHOD_INDEX == flags.nMethodId, + bCallIsOneway ); + } + else if( pAttributeType ) + { + pMultiJob->setAttributeType( pAttributeType, bIsSetter, bCallIsOneway ); + } + else + { + OSL_ASSERT( 0 ); + } + + if( pLastRemoteI ) + pMultiJob->setInterface( pLastRemoteI ); + else + pMultiJob->setOid( *ppLastOid ); + } /* getMemberTypeDescription */ + else + { + delete pMultiJob; + pMultiJob = 0; + pLastRemoteI = 0; // stubs are released during dispose eitherway + disposeEnvironment(); + break; + } +#ifdef BRIDGES_URP_PROT + bIsOneWay = pMethodType && pMethodType->bOneWay; + sMemberName = pMethodType ? + pMethodType->aBase.pMemberName : + pAttributeType->aBase.pMemberName; + sal_uInt32 nLogHeader = m_unmarshal.getPos(); +#endif + if( ! pMultiJob->extract( ) ) + { + // severe error during extracting, dispose + delete pMultiJob; + pMultiJob = 0; + pLastRemoteI = 0; // stubs are released during dispose eitherway + disposeEnvironment(); + break; + } + +#ifdef BRIDGES_URP_PROT + urp_logServingRequest( + m_pBridgeImpl, m_unmarshal.getPos() - nLogStart, + m_unmarshal.getPos() - nLogHeader, + !bIsOneWay, + sMemberName ); +#endif + if ( flags.bBridgePropertyCall ) + { + // call to the bridge internal object. + // these calls MUST be executed within the dispatcher thread in order + // to synchronize properly with protocol changes + // NOTE : Threadid is not preserved for this call. + + // lock the marshaling NOW ! + { + MutexGuard guard( m_pBridgeImpl->m_marshalingMutex ); + + pMultiJob->execute(); + + if( m_pBridgeImpl->m_pPropertyObject->changesHaveBeenCommited() ) + { + Properties props; + props = m_pBridgeImpl->m_pPropertyObject->getCommitedChanges(); + + // This call modified the protocol, apply the changes NOW ! + m_pBridgeImpl->applyProtocolChanges( props ); + } + } + delete pMultiJob; + pMultiJob = 0; + } + } + else + { + //-------------------------- + // handle reply + //-------------------------- + if( pMultiJob ) + { + pMultiJob->initiate(); + pMultiJob = 0; + } + if( pLastRemoteI ) + { + pLastRemoteI->release( pLastRemoteI ); + pLastRemoteI = 0; + } + ClientJob *pClientJob = + m_pBridgeImpl->m_clientJobContainer.remove( *( ByteSequence * )ppLastTid ); + + // Bridge MUST be already disposed, otherwise we got a wrong threadid + // from remote ! + OSL_ASSERT( pClientJob || m_pBridgeImpl->m_bDisposed ); + if( ! pClientJob ) + { + OUStringBuffer error( 128 ); + error.appendAscii( "ThreadID " ); + OString o = byteSequence2HumanReadableString( *(ByteSequence* )ppLastTid ); + error.appendAscii( o.getStr(), o.getLength() ); + error.appendAscii( " unknown, so couldn't unmarshal reply" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + pLastRemoteI = 0; + disposeEnvironment(); + break; + } + + pClientJob->m_bExceptionOccured = flags.bException; + + pClientJob->setUnmarshal( &m_unmarshal ); +#ifdef BRIDGES_URP_PROT + sMemberName = pClientJob->m_pMethodType ? + pClientJob->m_pMethodType->aBase.pMemberName : + pClientJob->m_pAttributeType->aBase.pMemberName; + sal_uInt32 nLogHeader = m_unmarshal.getPos(); +#endif + if( ! pClientJob->extract( ) ) + { + // severe error during extracting, dispose + pLastRemoteI = 0; // stubs are released during dispose eitherway + disposeEnvironment(); + break; + } +#ifdef BRIDGES_URP_PROT + urp_logGettingReply( + m_pBridgeImpl, m_unmarshal.getPos() - nLogStart, + m_unmarshal.getPos() - nLogHeader, sMemberName ); +#endif + sal_Bool bBridgePropertyCallAndWaitingForReply = + pClientJob->isBridgePropertyCall(); + + pClientJob->initiate(); + + if( bBridgePropertyCallAndWaitingForReply ) + { + // NOTE : This must be the reply for commit change. The new properties + // are now applied by the clientJob thread, but the reader thread + // must wait for it, because the next message on the wire already + // uses the new protocol settings. + // waiting for the commit change reply + m_pBridgeImpl->m_pPropertyObject->waitUntilChangesAreCommitted(); + } + } + } // end while( !m_unmarshal.finished() ) + + if( pLastRemoteI ) + pLastRemoteI->release( pLastRemoteI ); + + if( pMultiJob ) + pMultiJob->initiate(); + + if( pEnvRemote ) + pEnvRemote->release( pEnvRemote ); + } + + if( m_pConnection ) + { + m_pConnection->release( m_pConnection ); + m_pConnection = 0; + } +} +} diff --git a/bridges/source/remote/urp/urp_reader.hxx b/bridges/source/remote/urp/urp_reader.hxx new file mode 100644 index 000000000000..85968a57f70d --- /dev/null +++ b/bridges/source/remote/urp/urp_reader.hxx @@ -0,0 +1,78 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <osl/thread.hxx> + +#include "urp_unmarshal.hxx" + +struct remote_Connection; +typedef struct _uno_Environment uno_Environment; + +namespace bridges_urp +{ + +class OWriterThread; +struct MessageFlags; + +class OReaderThread : + public ::osl::Thread +{ +public: + OReaderThread( remote_Connection *pConnection , + uno_Environment *pEnvRemote, + OWriterThread *pWriterThread ); + ~OReaderThread(); + + // may only be called in the callstack of this thread !!!!! + // run() -> disposeEnvironment() -> dispose() -> destroyYourself() + void destroyYourself(); + +private: + virtual void SAL_CALL run(); + virtual void SAL_CALL onTerminated(); + + inline sal_Bool readBlock( sal_Int32 *pnMessageCount ); + inline sal_Bool readFlags( struct MessageFlags *pFlags ); + + void disposeEnvironment(); + + inline sal_Bool getMemberTypeDescription( + typelib_InterfaceAttributeTypeDescription **ppAttributeType, + typelib_InterfaceMethodTypeDescription **ppMethodType, + sal_Bool *pbIsSetter, + sal_uInt16 nMethodId , + typelib_TypeDescriptionReference *pITypeRef); + + remote_Connection *m_pConnection; + uno_Environment *m_pEnvRemote; + OWriterThread *m_pWriterThread; + sal_Bool m_bDestroyMyself; + sal_Bool m_bContinue; + urp_BridgeImpl *m_pBridgeImpl; + Unmarshal m_unmarshal; +}; + +} diff --git a/bridges/source/remote/urp/urp_replycontainer.hxx b/bridges/source/remote/urp/urp_replycontainer.hxx new file mode 100644 index 000000000000..afb1d951f5a0 --- /dev/null +++ b/bridges/source/remote/urp/urp_replycontainer.hxx @@ -0,0 +1,75 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <hash_map> +#include <list> + +#include <osl/mutex.hxx> +#include <osl/diagnose.h> + +#include "urp_threadid.hxx" + +namespace bridges_urp +{ + class ClientJob; + typedef ::std::hash_map< ::rtl::ByteSequence , + ::std::list < ClientJob * > , + HashThreadId , + EqualThreadId > Id2ClientJobStackMap; + + class urp_ClientJobContainer + { + public: + void add( const ::rtl::ByteSequence &id , ClientJob *p ) + { + ::osl::MutexGuard guard( m_mutex ); + m_map[id].push_back( p ); + } + + ClientJob *remove( const ::rtl::ByteSequence & id ) + { + ::osl::MutexGuard guard( m_mutex ); + Id2ClientJobStackMap::iterator ii = m_map.find( id ); + + ClientJob *p = 0; + if( ii != m_map.end() ) + { + p = (*ii).second.back(); + (*ii).second.pop_back(); + if( (*ii).second.empty() ) + { + m_map.erase( ii ); + } + } + + return p; + } + + private: + ::osl::Mutex m_mutex; + Id2ClientJobStackMap m_map; + }; +} diff --git a/bridges/source/remote/urp/urp_threadid.cxx b/bridges/source/remote/urp/urp_threadid.cxx new file mode 100644 index 000000000000..6d8d165be26e --- /dev/null +++ b/bridges/source/remote/urp/urp_threadid.cxx @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include "urp_threadid.hxx" + +#include <rtl/strbuf.hxx> + +using namespace rtl; + +namespace bridges_urp +{ + rtl::OString byteSequence2HumanReadableString( const rtl::ByteSequence &a ) + { + const sal_uInt8 *p = (const sal_uInt8 * ) a.getConstArray(); + sal_Int32 nLength = a.getLength(); + OStringBuffer buf( a.getLength() * 2 + 2 ); + buf.append( RTL_CONSTASCII_STRINGPARAM( "0x" ) ); + for( sal_Int32 i = 0 ; i < nLength ; i ++ ) + buf.append( (sal_Int32) p[i] , 16 ); + return buf.makeStringAndClear(); + } +} diff --git a/bridges/source/remote/urp/urp_threadid.hxx b/bridges/source/remote/urp/urp_threadid.hxx new file mode 100644 index 000000000000..cd95d89b2af2 --- /dev/null +++ b/bridges/source/remote/urp/urp_threadid.hxx @@ -0,0 +1,59 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _URP_THREADID_HXX_ +#define _URP_THREADID_HXX_ + +#include <sal/types.h> +#include <rtl/byteseq.hxx> +#include <rtl/string.hxx> + +namespace bridges_urp +{ + + struct EqualThreadId + { + sal_Int32 operator () ( const ::rtl::ByteSequence &a , const ::rtl::ByteSequence &b ) const + { + return a == b; + } + }; + + struct HashThreadId + { + sal_Int32 operator () ( const ::rtl::ByteSequence &a ) const + { + if( a.getLength() >= 4 ) + { + return *(sal_Int32*) a.getConstArray(); + } + return 0; + } + }; + + rtl::OString byteSequence2HumanReadableString( const rtl::ByteSequence &a ); +} +#endif diff --git a/bridges/source/remote/urp/urp_unmarshal.cxx b/bridges/source/remote/urp/urp_unmarshal.cxx new file mode 100644 index 000000000000..79335bfeb6f0 --- /dev/null +++ b/bridges/source/remote/urp/urp_unmarshal.cxx @@ -0,0 +1,707 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <string.h> + +#include <osl/diagnose.h> + +#include <rtl/alloc.h> +#include <rtl/ustrbuf.hxx> + +#include <uno/data.h> +#include <uno/any2.h> +#include <uno/sequence2.h> + +#include <com/sun/star/uno/Any.hxx> + +#include "urp_unmarshal.hxx" +#include "urp_bridgeimpl.hxx" + + +using namespace ::rtl; +using namespace ::com::sun::star::uno; + +namespace bridges_urp +{ +static int g_nDetectLittleEndian = 1; +char g_bSystemIsLittleEndian = ((char*)&g_nDetectLittleEndian)[0]; + + +Unmarshal::Unmarshal( struct urp_BridgeImpl *pBridgeImpl, + uno_Environment *pEnvRemote, + remote_createStubFunc callback ) : + m_nBufferSize( 4096 ), + m_base( (sal_Int8*) rtl_allocateMemory( m_nBufferSize ) ), + m_pos( m_base ), + m_nLength( 0 ), + m_callback( callback ), + m_pEnvRemote( pEnvRemote ), + m_pBridgeImpl( pBridgeImpl ) +{ +} + +Unmarshal::~Unmarshal() +{ + rtl_freeMemory( m_base ); +} + +// special unpacks +sal_Bool Unmarshal::unpackTid( sal_Sequence **ppThreadId ) +{ + sal_Int32 nSize; + sal_Bool bReturn = unpackCompressedSize( &nSize ); + if( bReturn ) + { + if( nSize ) + { + rtl_byte_sequence_constructFromArray( ppThreadId , m_pos , nSize ); + m_pos += nSize; + sal_uInt16 nIndex; + bReturn = unpackInt16( &nIndex ); + if( nIndex < m_pBridgeImpl->m_properties.nTidCacheSize ) + { + m_pBridgeImpl->m_pTidIn[nIndex] = *(ByteSequence * )ppThreadId; + } + else if( 0xffff != nIndex ) + { + bReturn = sal_False; + rtl_byte_sequence_construct( ppThreadId , 0 ); + + OUStringBuffer error( 128 ); + error.appendAscii( "cache index for tid " ); + OString o = byteSequence2HumanReadableString( *(ByteSequence * ) ppThreadId ); + error.appendAscii( o.getStr(), o.getLength() ); + error.appendAscii( "out of range(0x"); + error.append( (sal_Int32) nIndex ,16 ); + error.appendAscii( ")" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + } + else + { + sal_uInt16 nIndex; + bReturn = unpackInt16( &nIndex ); + if( nIndex < m_pBridgeImpl->m_properties.nTidCacheSize ) + { + *ppThreadId = m_pBridgeImpl->m_pTidIn[nIndex].getHandle(); + rtl_byte_sequence_acquire( *ppThreadId ); + } + else + { + bReturn = sal_False; + rtl_byte_sequence_construct( ppThreadId , 0 ); + OUStringBuffer error(128); + error.appendAscii( "cache index for tids out of range(0x" ); + error.append( (sal_Int32) nIndex ,16 ); + error.appendAscii( ")" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + } + } + else + { + m_pBridgeImpl->addError( "couldn't unpack thread id because of previous errors" ); + } + return bReturn; +} + +sal_Bool Unmarshal::unpackOid( rtl_uString **ppOid ) +{ + sal_Bool bReturn = sal_True; + sal_uInt16 nCacheIndex = 0; + + bReturn = bReturn && unpackString( ppOid ); + bReturn = bReturn && unpackInt16( &nCacheIndex ); + + if( bReturn && + ! ( 0xffff == nCacheIndex && 0 == (*ppOid)->length ) /* null reference */ ) + { + if( (*ppOid)->length ) + { + // new unknown reference + if( 0xffff != nCacheIndex ) + { + // oid should be cached ? + if( nCacheIndex < m_pBridgeImpl->m_properties.nOidCacheSize ) + { + m_pBridgeImpl->m_pOidIn[nCacheIndex] = *ppOid; + } + else + { + OUStringBuffer error( 128 ); + error.appendAscii( "new oid provided (" ); + error.append( *ppOid ); + error.appendAscii( "), but new cache index is out of range(0x"); + error.append( (sal_Int32) nCacheIndex ,16 ); + error.appendAscii( ")" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + + bReturn = sal_False; + rtl_uString_new( ppOid ); + } + } + } + else + { + // reference in cache ! + if( nCacheIndex < m_pBridgeImpl->m_properties.nOidCacheSize ) + { + rtl_uString_assign( ppOid , m_pBridgeImpl->m_pOidIn[nCacheIndex].pData ); + } + else + { + bReturn = sal_False; + rtl_uString_new( ppOid ); + + OUStringBuffer error( 128 ); + error.appendAscii( "cache index for oids out of range(0x"); + error.append( (sal_Int32) nCacheIndex ,16 ); + error.appendAscii( ")" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + } + } + + return bReturn; +} + +sal_Bool Unmarshal::unpack( void *pDestination , + typelib_TypeDescription *pTypeDescr ) +{ + // Note: We implement unpack functionality without recursions in order + // to avoid stack overflows caused by rotten URP blocks. + + m_aItemsToUnpack.push( UnpackItem( pDestination, pTypeDescr ) ); + + sal_Bool bReturn = sal_True; + do + { + void * pDest = m_aItemsToUnpack.top().pDest; + typelib_TypeDescription * pType = m_aItemsToUnpack.top().pType; + m_aItemsToUnpack.pop(); + + switch( pType->eTypeClass ) + { + case typelib_TypeClass_VOID: + // do nothing + break; + case typelib_TypeClass_BYTE: + { + bReturn = unpackInt8( pDest ); + break; + } + case typelib_TypeClass_BOOLEAN: + { + bReturn = ! checkOverflow( 1 ); + if( bReturn ) + { + *((sal_Bool*)pDest) = (sal_Bool ) ( *m_pos); + m_pos ++; + } + else + { + *((sal_Bool*)pDest) = 0; + } + break; + } + + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + { + unpackInt16( pDest ); + break; + } + case typelib_TypeClass_ENUM: + case typelib_TypeClass_FLOAT: + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + { + bReturn = unpackInt32( pDest ); + break; + } + case typelib_TypeClass_DOUBLE: + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + { + sal_Int8 * p = static_cast< sal_Int8 * >(pDest); + bReturn = ! checkOverflow( 8 ); + if( bReturn ) + { + if( isSystemLittleEndian() ) + { + p[7] = m_pos[0]; + p[6] = m_pos[1]; + p[5] = m_pos[2]; + p[4] = m_pos[3]; + p[3] = m_pos[4]; + p[2] = m_pos[5]; + p[1] = m_pos[6]; + p[0] = m_pos[7]; + } + else + { + p[0] = m_pos[0]; + p[1] = m_pos[1]; + p[2] = m_pos[2]; + p[3] = m_pos[3]; + p[4] = m_pos[4]; + p[5] = m_pos[5]; + p[6] = m_pos[6]; + p[7] = m_pos[7]; + } + m_pos += 8; + } + else + { + // Do not trigger alignment errors: + p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = 0; + } + break; + } + case typelib_TypeClass_STRING: + { + unpackString( pDest ); + break; + } + case typelib_TypeClass_ANY: + { + uno_Any *pAny = ( uno_Any * )pDest; + + pAny->pType = 0; + // Type is acquired with typelib_typedescription_acquire + + bReturn = unpackType( &(pAny->pType) ); + + typelib_TypeDescription *pDataType = 0; + if( bReturn && pAny->pType ) + { + typelib_typedescriptionreference_getDescription( &pDataType , pAny->pType ); + + if( pDataType ) + { + switch (pDataType->eTypeClass) + { + case typelib_TypeClass_HYPER: + case typelib_TypeClass_UNSIGNED_HYPER: + if (sizeof(void *) < sizeof(sal_Int64)) + { + pAny->pData = rtl_allocateMemory( sizeof(sal_Int64) ); + } + else + { + pAny->pData = &pAny->pReserved; + } + break; + case typelib_TypeClass_FLOAT: + if (sizeof(void *) < sizeof(float)) + { + pAny->pData = rtl_allocateMemory( sizeof(float) ); + } + else + { + pAny->pData = &pAny->pReserved; + } + break; + case typelib_TypeClass_DOUBLE: + if (sizeof(void *) < sizeof(double)) + { + pAny->pData = rtl_allocateMemory( sizeof(double) ); + } + else + { + pAny->pData = &pAny->pReserved; + } + break; + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_UNION: + case typelib_TypeClass_EXCEPTION: + case typelib_TypeClass_ARRAY: + pAny->pData = rtl_allocateMemory( pDataType->nSize ); + break; + case typelib_TypeClass_ANY: + { + m_pBridgeImpl->addError( + OUString( RTL_CONSTASCII_USTRINGPARAM( + "can't unmarshal any: any in any not supported!" ) ) ); + + pAny->pData = 0; + Type type; // void + pAny->pType = type.getTypeLibType(); + typelib_typedescriptionreference_acquire( pAny->pType ); + + bReturn = sal_False; + break; + } + default: + pAny->pData = &pAny->pReserved; + } + + if ( bReturn ) + { + m_aItemsToUnpack.push( + UnpackItem( pAny->pData, pDataType ) ); + } + } + else + { + OUStringBuffer error; + error.appendAscii( "can't unmarshal any because typedescription for " ); + error.append( pAny->pType->pTypeName ); + error.appendAscii( " is missing" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + } + + if( pDataType ) + { + typelib_typedescription_release( pDataType ); + } + else + { + pAny->pData = 0; + Type type; // void + pAny->pType = type.getTypeLibType(); + typelib_typedescriptionreference_acquire( pAny->pType ); + + bReturn = sal_False; + } + + break; + } + case typelib_TypeClass_INTERFACE: + { + *(remote_Interface**)pDest = 0; + + rtl_uString *pString = 0; + bReturn = unpackOid( &pString ) && bReturn; + + if( bReturn && pString && pString->length ) + { + m_callback( (remote_Interface**) pDest , + pString, + pType->pWeakRef , + m_pEnvRemote, + urp_releaseRemoteCallback ); + } + if( pString ) + { + rtl_uString_release( pString ); + } + break; + } + case typelib_TypeClass_TYPE: + { + bReturn = unpackType( pDest ); + break; + } + case typelib_TypeClass_STRUCT: + case typelib_TypeClass_EXCEPTION: + { + typelib_CompoundTypeDescription * pCompType = + (typelib_CompoundTypeDescription *)pType; + + // direct members + typelib_TypeDescriptionReference ** ppTypeRefs = pCompType->ppTypeRefs; + sal_Int32 * pMemberOffsets = pCompType->pMemberOffsets; + sal_Int32 nDescr = pCompType->nMembers; + + // at least assume 1 byte per member + bReturn = bReturn && ! checkOverflow( nDescr * 1 ); + for ( sal_Int32 nPos = nDescr; nPos; --nPos ) + { + typelib_TypeDescription * pMemberType = 0; + typelib_typedescriptionreference_getDescription( + &pMemberType, ppTypeRefs[ nPos - 1 ] ); + + m_aItemsToUnpack.push( + UnpackItem( (char*)pDest + pMemberOffsets[ nPos - 1 ], + pMemberType, + true /* construct even in error case */ ) ); + + m_aTypesToRelease.push_back( pMemberType ); + } + + // parent + if (pCompType->pBaseTypeDescription) + { + m_aItemsToUnpack.push( + UnpackItem( pDest, + (typelib_TypeDescription *) + pCompType->pBaseTypeDescription ) ); + } + break; + } + case typelib_TypeClass_SEQUENCE: + { + sal_Int32 nLen; + bReturn = unpackCompressedSize( &nLen ); + + // urp protocol does not allow to use the elementsize as a guess, if enough data + // is available. However, at least one byte per member must be within the message + bReturn = bReturn && ! checkOverflow( 1 * nLen ); + uno_Sequence *pSequence = 0; + if( nLen && bReturn ) + { + typelib_TypeDescriptionReference * pETRef = + ((typelib_IndirectTypeDescription *)pType)->pType; + + typelib_TypeDescription * pET = 0; + typelib_typedescriptionreference_getDescription( &pET , pETRef ); + + if( pET ) + { + sal_Int32 nElementSize = pET->nSize; + + pSequence = (uno_Sequence *)rtl_allocateMemory( + SAL_SEQUENCE_HEADER_SIZE + nElementSize * nLen ); + pSequence->nRefCount = 1; + pSequence->nElements = nLen; + + if( typelib_TypeClass_BYTE == pET->eTypeClass ) + { + memcpy( pSequence->elements , m_pos , nLen ); + m_pos += nLen; + } + else + { + for ( sal_Int32 i = nLen; i; --i ) + { + m_aItemsToUnpack.push( + UnpackItem( + ((char*)pSequence->elements) + + (i - 1) * nElementSize, + pET ) ); + } + } + m_aTypesToRelease.push_back( pET ); + } + else + { + bReturn = sal_False; + uno_constructData( &pSequence , pType ); + OUStringBuffer error; + error.appendAscii( "can't unmarshal sequence, because there is no typedescription for element type " ); + error.append( pETRef->pTypeName ); + error.appendAscii( " available" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + } + else + { + uno_constructData( &pSequence , pType ); + } + + *((uno_Sequence **)pDest) = pSequence; + break; + } + case typelib_TypeClass_UNION: + case typelib_TypeClass_ARRAY: + case typelib_TypeClass_SERVICE: + case typelib_TypeClass_MODULE: + case typelib_TypeClass_INTERFACE_METHOD: + case typelib_TypeClass_INTERFACE_ATTRIBUTE: + case typelib_TypeClass_UNKNOWN: + default: + { + ::rtl::OUStringBuffer buffer( 128 ); + buffer.appendAscii( RTL_CONSTASCII_STRINGPARAM("Unsupported typeclass during unmarshaling (")); + buffer.append( ( sal_Int32 ) pType->eTypeClass , 10 ); + buffer.appendAscii( ")" ); + m_pBridgeImpl->addError( buffer.makeStringAndClear() ); + bReturn = sal_False; + } + } + + if ( !bReturn ) + { + // construct default data for every remaining item. + while ( !m_aItemsToUnpack.empty() ) + { + const UnpackItem & rItem = m_aItemsToUnpack.top(); + + if ( rItem.bMustBeConstructed ) + uno_constructData( rItem.pDest , rItem.pType ); + + m_aItemsToUnpack.pop(); + } + } + } + while ( !m_aItemsToUnpack.empty() ); + + // release pending type descriptions + TypeDescVector::const_iterator it = m_aTypesToRelease.begin(); + const TypeDescVector::const_iterator end = m_aTypesToRelease.end(); + while ( it != end ) + { + typelib_typedescription_release( *it ); + it++; + } + m_aTypesToRelease.clear(); + + return bReturn; +} + +sal_Bool Unmarshal::unpackType( void *pDest ) +{ + *(typelib_TypeDescriptionReference **) pDest = 0; + + sal_uInt8 nTypeClass; + sal_Bool bReturn = unpackInt8( &nTypeClass ); + + typelib_TypeDescriptionReference *pTypeRef = 0; + if( bReturn ) + { + if( nTypeClass <= 14 /* any */ ) + { + pTypeRef = * typelib_static_type_getByTypeClass((typelib_TypeClass )nTypeClass); + typelib_typedescriptionreference_acquire( pTypeRef ); + } + else + { + sal_uInt16 nCacheIndex = 0; + bReturn = bReturn && unpackInt16( &nCacheIndex ); + + if( bReturn ) + { + if( nTypeClass & 0x80 ) + { + // new type + rtl_uString *pString = 0; + bReturn = bReturn && unpackString( &pString ); + if( bReturn ) + { + typelib_TypeDescription *pType = 0; + typelib_typedescription_getByName( &pType, pString ); + if( pType ) + { + // type is known in this process + if( (typelib_TypeClass )(nTypeClass & 0x7f) == pType->eTypeClass ) + { + //typename and typeclass match, this is as it should be + pTypeRef = pType->pWeakRef; + typelib_typedescriptionreference_acquire( pTypeRef ); + } + else + { + // typename and typeclass do not match, dispose the bridge + // as there must be inconsistent type base between both processes + // or trash comes over the wire ... + bReturn = sal_False; + OUStringBuffer error( 128 ); + error.appendAscii( "it is tried to introduce type " ); + error.append( pString ); + error.appendAscii( "with typeclass " ); + error.append( (sal_Int32)( nTypeClass & 0x7f ) , 10 ); + error.appendAscii( " , which does not match with typeclass " ); + error.append( (sal_Int32) pType->eTypeClass ,10 ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + typelib_typedescription_release( pType ); + pType = 0; + } + else + { + // a type by this name is not known in the process. + if( (nTypeClass & 0x7f) < typelib_TypeClass_UNKNOWN ) + { + // typeclass is within a valid range, introduce the new + // type. + typelib_typedescriptionreference_new( + &pTypeRef, (typelib_TypeClass )(nTypeClass & 0x7f), pString ); + } + else + { + // typeclass is out of range ! + bReturn = sal_False; + OUStringBuffer error( 128 ); + error.appendAscii( "it is tried to introduce type " ); + error.append( pString ); + error.appendAscii( "with an out of range typeclass " ); + error.append( (sal_Int32)( nTypeClass & 0x7f ) , 10 ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + } + + if( bReturn && nCacheIndex != 0xffff ) + { + if( nCacheIndex < m_pBridgeImpl->m_properties.nTypeCacheSize ) + { + m_pBridgeImpl->m_pTypeIn[nCacheIndex] = *( Type * )&pTypeRef; + } + else + { + bReturn = sal_False; + OUStringBuffer error( 128 ); + error.appendAscii( "cache index for type " ); + error.append( pString ); + error.appendAscii( "out of range(0x" ); + error.append( (sal_Int32) nCacheIndex ,16 ); + error.appendAscii( ")" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + } + } + if( pString ) + { + rtl_uString_release( pString ); + } + } + else + { + if( nCacheIndex < m_pBridgeImpl->m_properties.nTypeCacheSize ) + { + pTypeRef = m_pBridgeImpl->m_pTypeIn[nCacheIndex].getTypeLibType(); + typelib_typedescriptionreference_acquire( pTypeRef ); + } + else + { + bReturn = sal_False; + OUStringBuffer error; + error.appendAscii( "cache index for types out of range(0x" ); + error.append( (sal_Int32) nCacheIndex ,16 ); + error.appendAscii( ")" ); + m_pBridgeImpl->addError( error.makeStringAndClear() ); + } + } + } + } + } + if( ! pTypeRef ) + { + pTypeRef = * typelib_static_type_getByTypeClass(typelib_TypeClass_VOID); + typelib_typedescriptionreference_acquire( pTypeRef ); + } + // pTypeRef is already acquired + *(typelib_TypeDescriptionReference**)pDest = pTypeRef; + return bReturn; +} + +} + diff --git a/bridges/source/remote/urp/urp_unmarshal.hxx b/bridges/source/remote/urp/urp_unmarshal.hxx new file mode 100644 index 000000000000..60da3f2d8b95 --- /dev/null +++ b/bridges/source/remote/urp/urp_unmarshal.hxx @@ -0,0 +1,280 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _URP_UNMARSHAL_HXX_ +#define _URP_UNMARSHAL_HXX_ + +#include <stack> +#include <vector> +#include <rtl/byteseq.hxx> +#include <rtl/ustrbuf.hxx> +#include <bridges/remote/context.h> + +#ifndef _BRIDGES_REMOTE_HELPER_HXX_ +#include <bridges/remote/helper.hxx> +#endif +#include <com/sun/star/uno/Type.hxx> +#include "urp_bridgeimpl.hxx" + +typedef struct _uno_Environment uno_Environment; +struct remote_Interface; + +namespace bridges_urp +{ + +extern char g_bSystemIsLittleEndian; +class ThreadId; +struct urp_BridgeImpl; +void SAL_CALL urp_releaseRemoteCallback( + remote_Interface *pRemoteI,rtl_uString *pOid, + typelib_TypeDescriptionReference *pTypeRef, + uno_Environment *pEnvRemote ); + +struct UnpackItem +{ + void * pDest; + typelib_TypeDescription * pType; + bool bMustBeConstructed; + + UnpackItem() + : pDest( 0 ), pType( 0 ), bMustBeConstructed( false ) {} + UnpackItem( void * d, typelib_TypeDescription * t, bool b = false ) + : pDest( d ), pType( t ), bMustBeConstructed( b ) {} +}; + +typedef std::stack< UnpackItem > UnpackItemStack; +typedef std::vector< typelib_TypeDescription * > TypeDescVector; + +class Unmarshal +{ +public: + Unmarshal( + struct urp_BridgeImpl *, + uno_Environment *pEnvRemote, + remote_createStubFunc callback ); + ~Unmarshal(); + + inline sal_Bool finished() + { return m_base + m_nLength == m_pos; } + inline sal_uInt32 getPos() + { return (sal_uInt32 ) (m_pos - m_base); } + + inline sal_Bool setSize( sal_Int32 nSize ); + + sal_Bool unpack( void *pDest, typelib_TypeDescription *pType ); + inline sal_Bool unpackCompressedSize( sal_Int32 *pData ); + inline sal_Bool unpackInt8( void *pDest ); + inline sal_Bool unpackString( void *pDest ); + inline sal_Bool unpackInt16( void *pDest ); + inline sal_Bool unpackInt32( void *pDest ); + sal_Bool unpackType( void *pDest ); + + inline sal_Bool unpackAny( void *pDest ); + sal_Bool unpackOid( rtl_uString **ppOid ); + sal_Bool unpackTid( sal_Sequence **ppThreadId ); + + sal_Int8 *getBuffer() + { return m_base; } + inline sal_Bool isSystemLittleEndian() + { return g_bSystemIsLittleEndian; } + +private: + inline sal_Bool checkOverflow( sal_Int32 nNextMem ); + + UnpackItemStack m_aItemsToUnpack; + TypeDescVector m_aTypesToRelease; + + sal_Int32 m_nBufferSize; + sal_Int8 *m_base; + sal_Int8 *m_pos; + sal_Int32 m_nLength; + + remote_createStubFunc m_callback; + uno_Environment *m_pEnvRemote; + urp_BridgeImpl *m_pBridgeImpl; +}; + +inline sal_Bool Unmarshal::setSize( sal_Int32 nSize ) +{ + if( nSize > m_nBufferSize ) + { + // adjust buffer size and length. + sal_Int8 * base = + (sal_Int8*)rtl_reallocateMemory (m_base, sal_Size(nSize)); + if (base != 0) + { + m_base = base; + m_nLength = m_nBufferSize = nSize; + } + } + else + { + // adjust buffer length, only. + m_nLength = nSize; + } + + // reset buffer position, and leave. + m_pos = m_base; + return (m_nLength == nSize); +} + +inline sal_Bool Unmarshal::checkOverflow( sal_Int32 nNextMem ) +{ + sal_Bool bOverflow = nNextMem < 0 || + (((sal_Int32)( m_pos - m_base )) + nNextMem ) > m_nLength; + if( bOverflow ) + m_pBridgeImpl->addError( "message too short" ); + return bOverflow; +} + + +inline sal_Bool Unmarshal::unpackInt8( void *pDest ) +{ + sal_Bool bReturn = ! checkOverflow( 1 ); + if( bReturn ) + { + *((sal_Int8*)pDest ) = *m_pos; + m_pos++; + } + else + { + *((sal_Int8*)pDest ) = 0; + } + return bReturn; +} + +inline sal_Bool Unmarshal::unpackInt32( void *pDest ) +{ + sal_uInt32 *p = ( sal_uInt32 * ) pDest; + sal_Bool bReturn = ! checkOverflow(4); + if( bReturn ) + { + if( isSystemLittleEndian() ) + { + ((sal_Int8*) p )[3] = m_pos[0]; + ((sal_Int8*) p )[2] = m_pos[1]; + ((sal_Int8*) p )[1] = m_pos[2]; + ((sal_Int8*) p )[0] = m_pos[3]; + } + else + { + ((sal_Int8*) p )[3] = m_pos[3]; + ((sal_Int8*) p )[2] = m_pos[2]; + ((sal_Int8*) p )[1] = m_pos[1]; + ((sal_Int8*) p )[0] = m_pos[0]; + } + m_pos += 4; + } + else + { + *p = 0; + } + return bReturn; +} + +inline sal_Bool Unmarshal::unpackInt16( void *pDest ) +{ + sal_uInt16 *p = ( sal_uInt16 * ) pDest; + + sal_Bool bReturn = ! checkOverflow( 2 ); + if( bReturn ) + { + if( isSystemLittleEndian() ) + { + ((sal_Int8*) p )[1] = m_pos[0]; + ((sal_Int8*) p )[0] = m_pos[1]; + } + else + { + ((sal_Int8*) p )[1] = m_pos[1]; + ((sal_Int8*) p )[0] = m_pos[0]; + } + m_pos ++; + m_pos ++; + } + else + { + *p = 0; + } + return bReturn; +} + +inline sal_Bool Unmarshal::unpackString( void *pDest ) +{ + sal_Int32 nLength; + sal_Bool bReturn = unpackCompressedSize( &nLength ); + + bReturn = bReturn && ! checkOverflow( nLength ); + if( bReturn ) + { + *(rtl_uString **) pDest = 0; + rtl_string2UString( (rtl_uString**) pDest, (const sal_Char * )m_pos , nLength, + RTL_TEXTENCODING_UTF8, OSTRING_TO_OUSTRING_CVTFLAGS ); + m_pos += nLength; + } + else + { + *(rtl_uString ** ) pDest = 0; + rtl_uString_new( (rtl_uString **) pDest ); + } + return bReturn; +} + +inline sal_Bool Unmarshal::unpackCompressedSize( sal_Int32 *pData ) +{ + sal_uInt8 n8Size; + sal_Bool bReturn = unpackInt8( &n8Size ); + if( bReturn ) + { + if( n8Size == 0xff ) + { + unpackInt32( pData ); + } + else + { + *pData = (sal_Int32 ) n8Size; + } + } + return bReturn; +} + +inline sal_Bool Unmarshal::unpackAny( void *pDest ) +{ + typelib_TypeDescriptionReference *pTypeRef = + * typelib_static_type_getByTypeClass( typelib_TypeClass_ANY ); + + typelib_TypeDescription * pTD = 0; + typelib_typedescriptionreference_getDescription( &pTD, pTypeRef ); + + sal_Bool bReturn = unpack( pDest, pTD ); + + typelib_typedescription_release( pTD ); + + return bReturn; +} + +} +#endif diff --git a/bridges/source/remote/urp/urp_writer.cxx b/bridges/source/remote/urp/urp_writer.cxx new file mode 100644 index 000000000000..610b6653a06c --- /dev/null +++ b/bridges/source/remote/urp/urp_writer.cxx @@ -0,0 +1,269 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_bridges.hxx" +#include <stdio.h> +#include <osl/time.h> + +#include <osl/mutex.hxx> +#include <osl/conditn.h> + +#include <typelib/typedescription.h> + +#include <bridges/remote/connection.h> +#include <bridges/remote/remote.hxx> + +#include <com/sun/star/uno/Sequence.hxx> + +#include <bridges/remote/counter.hxx> + +#include "urp_writer.hxx" +#include "urp_bridgeimpl.hxx" +#include "urp_marshal.hxx" +#include "urp_dispatch.hxx" + +#if OSL_DEBUG_LEVEL > 1 +static MyCounter thisCounter( "DEBUG : WriterThread" ); +#endif + +using namespace ::osl; + +namespace bridges_urp { + +OWriterThread::OWriterThread( remote_Connection *pConnection, urp_BridgeImpl *pBridgeImpl, + uno_Environment *pEnvRemote) : + m_bAbort( sal_False ), + m_bInBlockingWait( sal_False ), + m_bEnterBlockingWait( sal_False ), + m_pConnection( pConnection ), + m_pBridgeImpl( pBridgeImpl ), + m_pEnvRemote( pEnvRemote ) + +{ + m_oslCondition = osl_createCondition(); + osl_resetCondition( m_oslCondition ); + m_pConnection->acquire( m_pConnection ); + +#if OSL_DEBUG_LEVEL > 1 + thisCounter.acquire(); +#endif +} + +OWriterThread::~OWriterThread() +{ + osl_destroyCondition( m_oslCondition ); + m_pConnection->release( m_pConnection ); +#if OSL_DEBUG_LEVEL > 1 + thisCounter.release(); +#endif +} + + +// touch is called with locked m_marshalingMutex +void OWriterThread::touch( sal_Bool bImmediately ) +{ + if( bImmediately || m_pBridgeImpl->m_blockMarshaler.getPos() > m_pBridgeImpl->m_properties.nFlushBlockSize ) + { + write(); + } + else + { + // wake the writer thread up + if( m_bInBlockingWait ) + { + m_bInBlockingWait = sal_False; + osl_setCondition( m_oslCondition ); + } + else + { + // ensure, that the writing thread does not enter blocking mode + m_bEnterBlockingWait = sal_False; + } + } +} + + +void OWriterThread::abortThread() +{ + MutexGuard guard( m_pBridgeImpl->m_marshalingMutex ); + + m_bAbort = sal_True; + m_bEnterBlockingWait = sal_False; + if( m_bInBlockingWait ) + { + m_bInBlockingWait = sal_False; + osl_setCondition( m_oslCondition ); + } +} + + +// must be called with locked marshaling mutex +void OWriterThread::write() +{ + if( ! m_pBridgeImpl->m_blockMarshaler.empty() && ! m_bAbort ) + { + m_pBridgeImpl->m_blockMarshaler.finish( m_pBridgeImpl->m_nMarshaledMessages); + m_pBridgeImpl->m_nMarshaledMessages = 0; + + sal_Int32 nLength = m_pBridgeImpl->m_blockMarshaler.getSize(); + sal_Int8 *pBuf = m_pBridgeImpl->m_blockMarshaler.getBuffer(); + + if( nLength != m_pConnection->write( m_pConnection, pBuf, nLength )) + { + m_pBridgeImpl->m_blockMarshaler.restart(); + return; + } + m_pConnection->flush( m_pConnection ); + m_pBridgeImpl->m_blockMarshaler.restart(); + } +} + +void OWriterThread::sendEmptyMessage() +{ + // must be called with locked marshaling mutex + sal_Int32 a[2] = {0,0}; + m_pConnection->write( m_pConnection , (sal_Int8*) a , sizeof( sal_Int32) *2 ); +} + +void OWriterThread::insertReleaseRemoteCall( + rtl_uString *pOid,typelib_TypeDescriptionReference *pTypeRef) +{ + { + ::osl::MutexGuard guard( m_releaseCallMutex ); + + struct RemoteReleaseCall call; + call.sOid = pOid; + call.typeInterface = pTypeRef; + m_lstReleaseCalls.push_back( call ); + } + { + MutexGuard guard( m_pBridgeImpl->m_marshalingMutex ); + if( m_bInBlockingWait ) + { + m_bInBlockingWait = sal_False; + osl_setCondition( m_oslCondition ); + } + else + { + // ensure, that the writing thread does not enter blocking mode + m_bEnterBlockingWait = sal_False; + } + } +} + +/* The release calls for doubled interfaces + * + * + ***/ +void OWriterThread::executeReleaseRemoteCalls() +{ + ::std::list< struct RemoteReleaseCall > lstReleaseCalls; + { + ::osl::MutexGuard guard( m_releaseCallMutex ); + lstReleaseCalls.swap( m_lstReleaseCalls ); + } + + for( ::std::list< struct RemoteReleaseCall >::iterator ii = lstReleaseCalls.begin(); + ii != lstReleaseCalls.end(); + ++ ii ) + { + struct RemoteReleaseCall &call = (*ii) ; + + typelib_TypeDescription *pInterfaceTypeDesc = 0; + typelib_TypeDescription *pReleaseMethod = 0; + + call.typeInterface.getDescription( &pInterfaceTypeDesc ); + if( ! pInterfaceTypeDesc->bComplete ) + { + typelib_typedescription_complete( &pInterfaceTypeDesc ); + } + + uno_Any any; + uno_Any *pAny = &any; + + typelib_typedescriptionreference_getDescription( + &pReleaseMethod , + ((typelib_InterfaceTypeDescription*)pInterfaceTypeDesc)->ppAllMembers[REMOTE_RELEASE_METHOD_INDEX] ); + + urp_sendRequest_internal( + m_pEnvRemote , pReleaseMethod, call.sOid.pData, + (typelib_InterfaceTypeDescription*) pInterfaceTypeDesc, 0, 0, + &pAny ); + + typelib_typedescription_release( pReleaseMethod ); + typelib_typedescription_release( pInterfaceTypeDesc ); + } +} + + +void OWriterThread::run() +{ + while( ! m_bAbort ) + { + sal_Bool bWait; + { + MutexGuard guard( m_pBridgeImpl->m_marshalingMutex ); + bWait = m_bEnterBlockingWait; + if( bWait ) + { + osl_resetCondition( m_oslCondition ); + m_bInBlockingWait = sal_True; + } + m_bEnterBlockingWait = sal_True; + } + + // wait for some notification + if( bWait ) + osl_waitCondition( m_oslCondition , 0 ); + // (m_bInBlockingWait = sal_False was set by the activating thread) + + if( m_bAbort ) + break; + + // Wait for the timeout + TimeValue value = { 0 , 1000 * m_pBridgeImpl->m_properties.nOnewayTimeoutMUSEC }; + osl_resetCondition( m_oslCondition ); + osl_waitCondition( m_oslCondition , &value ); + + // check if there are some release calls to be sent .... + executeReleaseRemoteCalls(); + + { + // write to the socket + MutexGuard guard( m_pBridgeImpl->m_marshalingMutex ); + if( ! m_pBridgeImpl->m_blockMarshaler.empty() ) + { + write(); + } + } + } +} + + +} + diff --git a/bridges/source/remote/urp/urp_writer.hxx b/bridges/source/remote/urp/urp_writer.hxx new file mode 100644 index 000000000000..f789c092fb98 --- /dev/null +++ b/bridges/source/remote/urp/urp_writer.hxx @@ -0,0 +1,83 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#include <list> + +#include <osl/conditn.h> +#include <osl/mutex.hxx> + +#include <rtl/ustring.hxx> + +#include <osl/thread.hxx> + +#include <com/sun/star/uno/Type.hxx> + +struct remote_Connection; + +namespace bridges_urp +{ + struct RemoteReleaseCall + { + ::rtl::OUString sOid; + ::com::sun::star::uno::Type typeInterface; + }; + + struct urp_BridgeImpl; + class OWriterThread : + public ::osl::Thread + { + public: + OWriterThread( remote_Connection *pConnection, + urp_BridgeImpl *m_pBridgeImpl, + uno_Environment *pEnvRemote); + ~OWriterThread( ); + + virtual void SAL_CALL run(); + + void touch( sal_Bool bImmediately ); + void sendEmptyMessage(); + + void abortThread(); + + void SAL_CALL insertReleaseRemoteCall ( + rtl_uString *pOid,typelib_TypeDescriptionReference *pTypeRef); + void SAL_CALL executeReleaseRemoteCalls(); + + private: + void write(); + oslCondition m_oslCondition; + sal_Bool m_bAbort; + sal_Bool m_bInBlockingWait; + sal_Bool m_bEnterBlockingWait; + remote_Connection *m_pConnection; + urp_BridgeImpl *m_pBridgeImpl; + uno_Environment *m_pEnvRemote; // this is held weak only + + ::osl::Mutex m_releaseCallMutex; + ::std::list< struct RemoteReleaseCall > m_lstReleaseCalls; + }; +} + |