summaryrefslogtreecommitdiff
path: root/bridges/source/remote/urp/urp_environment.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bridges/source/remote/urp/urp_environment.cxx')
-rw-r--r--bridges/source/remote/urp/urp_environment.cxx551
1 files changed, 551 insertions, 0 deletions
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 );
+}
+
+}