summaryrefslogtreecommitdiff
path: root/automation/source/communi/communi.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'automation/source/communi/communi.cxx')
-rw-r--r--automation/source/communi/communi.cxx596
1 files changed, 596 insertions, 0 deletions
diff --git a/automation/source/communi/communi.cxx b/automation/source/communi/communi.cxx
new file mode 100644
index 000000000000..e62e060ba89c
--- /dev/null
+++ b/automation/source/communi/communi.cxx
@@ -0,0 +1,596 @@
+/*************************************************************************
+ *
+ * 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_automation.hxx"
+#include <stdio.h>
+#if OSL_DEBUG_LEVEL > 1
+#define DEBUGPRINTF(x) { printf(x); fflush( stdout ); }
+#else
+#define DEBUGPRINTF(x)
+#endif
+#include <tools/debug.hxx>
+#include <vcl/svapp.hxx>
+#include <vos/socket.hxx>
+#include <tools/stream.hxx>
+#include <vcl/timer.hxx>
+#include <tools/fsys.hxx>
+
+#include <automation/communi.hxx>
+
+
+/* Um den Destruktor protected zu machen wurde unten das delete entfernt.
+ Die Methode wird ohnehin hucht benutzt.
+// delete *((AE*)pData+n);
+*/
+
+#undef SV_IMPL_PTRARR_SORT
+#define SV_IMPL_PTRARR_SORT( nm,AE )\
+_SV_IMPL_SORTAR_ALG( nm,AE )\
+ void nm::DeleteAndDestroy( USHORT nP, USHORT nL ) { \
+ if( nL ) {\
+ DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );\
+ for( USHORT n=nP; n < nP + nL; n++ ) \
+ DBG_ERROR("Das Element der Liste wurde nicht gelöscht"); \
+ SvPtrarr::Remove( nP, nL ); \
+ } \
+ } \
+_SV_SEEK_PTR( nm, AE )
+
+
+
+
+SV_IMPL_PTRARR_SORT( CommunicationLinkList, CommunicationLink* );
+
+NAMESPACE_VOS(OMutex) *pMPostUserEvent=NULL; // Notwendig, da nicht threadfest
+
+CommunicationLinkViaSocket::CommunicationLinkViaSocket( CommunicationManager *pMan, NAMESPACE_VOS(OStreamSocket) *pSocket )
+: SimpleCommunicationLinkViaSocket( pMan, pSocket )
+, nConnectionClosedEventId( 0 )
+, nDataReceivedEventId( 0 )
+, bShutdownStarted( FALSE )
+, bDestroying( FALSE )
+{
+ SetPutDataReceivedHdl(LINK( this, CommunicationLinkViaSocket, PutDataReceivedHdl ));
+ if ( !pMPostUserEvent )
+ pMPostUserEvent = new NAMESPACE_VOS(OMutex);
+ // this is necassary to prevent the running thread from sending the close event
+ // before the open event has been sent.
+ StartCallback();
+
+ create();
+}
+
+CommunicationLinkViaSocket::~CommunicationLinkViaSocket()
+{
+ bDestroying = TRUE;
+ StopCommunication();
+ while ( nConnectionClosedEventId || nDataReceivedEventId )
+ GetpApp()->Yield();
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMConnectionClosed );
+ if ( nConnectionClosedEventId )
+ {
+ GetpApp()->RemoveUserEvent( nConnectionClosedEventId );
+ nConnectionClosedEventId = 0;
+ INFO_MSG( CByteString("Event gelöscht"),
+ CByteString( "ConnectionClosedEvent aus Queue gelöscht"),
+ CM_MISC, NULL );
+ }
+ }
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMDataReceived );
+ if ( nDataReceivedEventId )
+ {
+ GetpApp()->RemoveUserEvent( nDataReceivedEventId );
+ nDataReceivedEventId = 0;
+ delete GetServiceData();
+ INFO_MSG( CByteString("Event gelöscht"),
+ CByteString( "DataReceivedEvent aus Queue gelöscht"),
+ CM_MISC, NULL );
+ }
+ }
+}
+
+BOOL CommunicationLinkViaSocket::ShutdownCommunication()
+{
+ if ( isRunning() )
+ {
+
+ terminate();
+ if ( GetStreamSocket() )
+ GetStreamSocket()->shutdown();
+
+ if ( GetStreamSocket() ) // Mal wieder nach oben verschoben, da sonst nicht vom Read runtergesprungen wird.
+ GetStreamSocket()->close();
+
+ resume(); // So daß das run auch die Schleife verlassen kann
+
+ join();
+
+ NAMESPACE_VOS(OStreamSocket) *pTempSocket = GetStreamSocket();
+ SetStreamSocket( NULL );
+ delete pTempSocket;
+
+// ConnectionClosed(); Wird am Ende des Thread gerufen
+
+ }
+ else
+ {
+ join();
+ }
+
+ return TRUE;
+}
+
+BOOL CommunicationLinkViaSocket::StopCommunication()
+{
+ if ( !bShutdownStarted )
+ {
+ return SimpleCommunicationLinkViaSocket::StopCommunication();
+ }
+ else
+ {
+ WaitForShutdown();
+ return TRUE;
+ }
+}
+
+
+IMPL_LINK( CommunicationLinkViaSocket, ShutdownLink, void*, EMPTYARG )
+{
+ if ( !IsCommunicationError() )
+ ShutdownCommunication();
+ return 0;
+}
+
+
+void CommunicationLinkViaSocket::WaitForShutdown()
+{
+ if ( !bShutdownStarted )
+ {
+ aShutdownTimer.SetTimeout( 30000 ); // Should be 30 Seconds
+ aShutdownTimer.SetTimeoutHdl( LINK( this, CommunicationLinkViaSocket, ShutdownLink ) );
+ aShutdownTimer.Start();
+ bShutdownStarted = TRUE;
+ }
+ if ( bDestroying )
+ {
+ while ( pMyManager && aShutdownTimer.IsActive() )
+ {
+ if ( IsCommunicationError() )
+ return;
+ GetpApp()->Yield();
+ }
+ ShutdownCommunication();
+ }
+}
+
+BOOL CommunicationLinkViaSocket::IsCommunicationError()
+{
+ return !isRunning() || SimpleCommunicationLinkViaSocket::IsCommunicationError();
+}
+
+void CommunicationLinkViaSocket::run()
+{
+ BOOL bWasError = FALSE;
+ while ( schedule() && !bWasError && GetStreamSocket() )
+ {
+ if ( bWasError |= !DoReceiveDataStream() )
+ continue;
+
+ TimeValue sNochEins = {0, 1000000};
+ while ( schedule() && bIsInsideCallback ) // solange der letzte Callback nicht beendet ist
+ sleep( sNochEins );
+ SetNewPacketAsCurrent();
+ StartCallback();
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMDataReceived );
+ NAMESPACE_VOS(OGuard) aGuard2( *pMPostUserEvent );
+ mlPutDataReceived.Call(this);
+ }
+ }
+ TimeValue sNochEins = {0, 1000000};
+ while ( schedule() && bIsInsideCallback ) // solange der letzte Callback nicht beendet ist
+ sleep( sNochEins );
+
+ StartCallback();
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMConnectionClosed );
+ NAMESPACE_VOS(OGuard) aGuard2( *pMPostUserEvent );
+ nConnectionClosedEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationLinkViaSocket, ConnectionClosed ) );
+ }
+}
+
+BOOL CommunicationLinkViaSocket::DoTransferDataStream( SvStream *pDataStream, CMProtocol nProtocol )
+{
+ if ( !isRunning() )
+ return FALSE;
+
+ return SimpleCommunicationLinkViaSocket::DoTransferDataStream( pDataStream, nProtocol );
+}
+
+/// Dies ist ein virtueller Link!!!
+long CommunicationLinkViaSocket::ConnectionClosed( void* EMPTYARG )
+{
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMConnectionClosed );
+ nConnectionClosedEventId = 0; // Achtung!! alles andere muß oben gemacht werden.
+ }
+ ShutdownCommunication();
+ return CommunicationLink::ConnectionClosed( );
+}
+
+/// Dies ist ein virtueller Link!!!
+long CommunicationLinkViaSocket::DataReceived( void* EMPTYARG )
+{
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMDataReceived );
+ nDataReceivedEventId = 0; // Achtung!! alles andere muß oben gemacht werden.
+ }
+ return CommunicationLink::DataReceived( );
+}
+
+IMPL_LINK( CommunicationLinkViaSocket, PutDataReceivedHdl, CommunicationLinkViaSocket*, EMPTYARG )
+{
+ nDataReceivedEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationLink, DataReceived ) );
+ return 0;
+}
+
+
+
+MultiCommunicationManager::MultiCommunicationManager( BOOL bUseMultiChannel )
+: CommunicationManager( bUseMultiChannel )
+, bGracefullShutdown( TRUE )
+{
+ ActiveLinks = new CommunicationLinkList;
+ InactiveLinks = new CommunicationLinkList;
+}
+
+MultiCommunicationManager::~MultiCommunicationManager()
+{
+ StopCommunication();
+
+ if ( bGracefullShutdown ) // first try to collect all callbacks for closing channels
+ {
+ Timer aTimeout;
+ aTimeout.SetTimeout( 40000 );
+ aTimeout.Start();
+ USHORT nLinkCount = 0;
+ USHORT nNewLinkCount = 0;
+ while ( aTimeout.IsActive() )
+ {
+ GetpApp()->Yield();
+ nNewLinkCount = GetCommunicationLinkCount();
+ if ( nNewLinkCount == 0 )
+ aTimeout.Stop();
+ if ( nNewLinkCount != nLinkCount )
+ {
+ aTimeout.Start();
+ nLinkCount = nNewLinkCount;
+ }
+ }
+ }
+
+ // Alles weghauen, was nicht rechtzeitig auf die Bäume gekommen ist
+ // Was bei StopCommunication übrig geblieben ist, da es sich asynchron austragen wollte
+ USHORT i = ActiveLinks->Count();
+ while ( i-- )
+ {
+ CommunicationLinkRef rTempLink = ActiveLinks->GetObject( i );
+ ActiveLinks->Remove( i );
+ rTempLink->InvalidateManager();
+ rTempLink->ReleaseReference();
+ }
+ delete ActiveLinks;
+
+ /// Die Links zwischen ConnectionClosed und Destruktor.
+ /// Hier NICHT gerefcounted, da sie sich sonst im Kreis festhaten würden,
+ /// da die Links sich erst in ihrem Destruktor austragen
+ i = InactiveLinks->Count();
+ while ( i-- )
+ {
+ CommunicationLinkRef rTempLink = InactiveLinks->GetObject( i );
+ InactiveLinks->Remove( i );
+ rTempLink->InvalidateManager();
+ }
+ delete InactiveLinks;
+}
+
+BOOL MultiCommunicationManager::StopCommunication()
+{
+ // Alle Verbindungen abbrechen
+ // ConnectionClosed entfernt die Links aus der Liste. Je nach Implementation syncron
+ // oder asyncron. Daher Von oben nach unten Abräumen, so daß sich nichts verschiebt.
+ USHORT i = ActiveLinks->Count();
+ int nFail = 0;
+ while ( i )
+ {
+ if ( !ActiveLinks->GetObject(i-1)->StopCommunication() )
+ nFail++; // Hochzählen, da Verbindung sich nicht (sofort) beenden lässt.
+ i--;
+ }
+
+ return nFail == 0;
+}
+
+BOOL MultiCommunicationManager::IsLinkValid( CommunicationLink* pCL )
+{
+ if ( ActiveLinks->Seek_Entry( pCL ) )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+USHORT MultiCommunicationManager::GetCommunicationLinkCount()
+{
+ return ActiveLinks->Count();
+}
+
+CommunicationLinkRef MultiCommunicationManager::GetCommunicationLink( USHORT nNr )
+{
+ return ActiveLinks->GetObject( nNr );
+}
+
+void MultiCommunicationManager::CallConnectionOpened( CommunicationLink* pCL )
+{
+ CommunicationLinkRef rHold(pCL); // Hält den Zeiger bis zum Ende des calls
+ ActiveLinks->C40_PTR_INSERT(CommunicationLink, pCL);
+ rHold->AddRef();
+
+ CommunicationManager::CallConnectionOpened( pCL );
+}
+
+void MultiCommunicationManager::CallConnectionClosed( CommunicationLink* pCL )
+{
+ CommunicationLinkRef rHold(pCL); // Hält denm Zeiger bis zum Ende des calls
+
+ CommunicationManager::CallConnectionClosed( pCL );
+
+ USHORT nPos;
+ if ( ActiveLinks->Seek_Entry( pCL, &nPos ) )
+ {
+ InactiveLinks->C40_PTR_INSERT(CommunicationLink, pCL); // Ohne Reference
+ ActiveLinks->Remove( nPos );
+ }
+ pCL->ReleaseReference();
+
+ bIsCommunicationRunning = ActiveLinks->Count() > 0;
+// delete pCL;
+#if OSL_DEBUG_LEVEL > 1
+ rHold->bFlag = TRUE;
+#endif
+}
+
+void MultiCommunicationManager::DestroyingLink( CommunicationLink *pCL )
+{
+ USHORT nPos;
+ if ( InactiveLinks->Seek_Entry( pCL, &nPos ) )
+ InactiveLinks->Remove( nPos );
+ pCL->InvalidateManager();
+}
+
+
+
+CommunicationManagerClient::CommunicationManagerClient( BOOL bUseMultiChannel )
+: MultiCommunicationManager( bUseMultiChannel )
+{
+ ByteString aApplication("Something inside ");
+ aApplication.Append( ByteString( DirEntry( Application::GetAppFileName() ).GetName(), gsl_getSystemTextEncoding() ) );
+ SetApplication( aApplication );
+}
+
+
+
+CommunicationManagerServerViaSocket::CommunicationManagerServerViaSocket( ULONG nPort, USHORT nMaxCon, BOOL bUseMultiChannel )
+: CommunicationManagerServer( bUseMultiChannel )
+, nPortToListen( nPort )
+, nMaxConnections( nMaxCon )
+, pAcceptThread( NULL )
+{
+}
+
+CommunicationManagerServerViaSocket::~CommunicationManagerServerViaSocket()
+{
+ StopCommunication();
+}
+
+BOOL CommunicationManagerServerViaSocket::StartCommunication()
+{
+ if ( !pAcceptThread )
+ pAcceptThread = new CommunicationManagerServerAcceptThread( this, nPortToListen, nMaxConnections );
+ return TRUE;
+}
+
+
+BOOL CommunicationManagerServerViaSocket::StopCommunication()
+{
+ // Erst den Acceptor anhalten
+ delete pAcceptThread;
+ pAcceptThread = NULL;
+
+ // Dann alle Verbindungen kappen
+ return CommunicationManagerServer::StopCommunication();
+}
+
+
+void CommunicationManagerServerViaSocket::AddConnection( CommunicationLink *pNewConnection )
+{
+ CallConnectionOpened( pNewConnection );
+}
+
+
+CommunicationManagerServerAcceptThread::CommunicationManagerServerAcceptThread( CommunicationManagerServerViaSocket* pServer, ULONG nPort, USHORT nMaxCon )
+: pMyServer( pServer )
+, pAcceptorSocket( NULL )
+, nPortToListen( nPort )
+, nMaxConnections( nMaxCon )
+, nAddConnectionEventId( 0 )
+, xmNewConnection( NULL )
+{
+ if ( !pMPostUserEvent )
+ pMPostUserEvent = new NAMESPACE_VOS(OMutex);
+ create();
+}
+
+
+CommunicationManagerServerAcceptThread::~CommunicationManagerServerAcceptThread()
+{
+#ifndef aUNX // Weil das Accept nicht abgebrochen werden kann, so terminiert wenigstens das Prog
+ // #62855# pl: gilt auch bei anderen Unixen
+ // die richtige Loesung waere natuerlich, etwas auf die pipe zu schreiben,
+ // was der thread als Abbruchbedingung erkennt
+ // oder wenigstens ein kill anstatt join
+ terminate();
+ if ( pAcceptorSocket )
+ pAcceptorSocket->close(); // Dann das Accept unterbrechen
+
+ join(); // Warten bis fertig
+
+ if ( pAcceptorSocket )
+ {
+ delete pAcceptorSocket;
+ pAcceptorSocket = NULL;
+ }
+#else
+ DEBUGPRINTF ("Destructor CommunicationManagerServerAcceptThread Übersprungen!!!! (wegen Solaris BUG)\n");
+#endif
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMAddConnection );
+ if ( nAddConnectionEventId )
+ {
+ GetpApp()->RemoveUserEvent( nAddConnectionEventId );
+ nAddConnectionEventId = 0;
+ CommunicationLinkRef xNewConnection = GetNewConnection();
+ INFO_MSG( CByteString("Event gelöscht"),
+ CByteString( "AddConnectionEvent aus Queue gelöscht"),
+ CM_MISC, xNewConnection );
+ xNewConnection->InvalidateManager();
+ xNewConnection.Clear(); // sollte das Objekt hier löschen
+ }
+ }
+}
+
+void CommunicationManagerServerAcceptThread::run()
+{
+ if ( !nPortToListen )
+ return;
+
+ pAcceptorSocket = new NAMESPACE_VOS(OAcceptorSocket)();
+ NAMESPACE_VOS(OInetSocketAddr) Addr;
+ Addr.setPort( nPortToListen );
+ pAcceptorSocket->setReuseAddr( 1 );
+ if ( !pAcceptorSocket->bind( Addr ) )
+ {
+ return;
+ }
+ if ( !pAcceptorSocket->listen( nMaxConnections ) )
+ {
+ return;
+ }
+
+
+ NAMESPACE_VOS(OStreamSocket) *pStreamSocket = NULL;
+
+ while ( schedule() )
+ {
+ pStreamSocket = new NAMESPACE_VOS(OStreamSocket);
+ switch ( pAcceptorSocket->acceptConnection( *pStreamSocket ) )
+ {
+ case NAMESPACE_VOS(ISocketTypes::TResult_Ok):
+ {
+ pStreamSocket->setTcpNoDelay( 1 );
+
+ TimeValue sNochEins = {0, 100};
+ while ( schedule() && xmNewConnection.Is() ) // Solange die letzte Connection nicht abgeholt wurde warten wir
+ sleep( sNochEins );
+ xmNewConnection = new CommunicationLinkViaSocket( pMyServer, pStreamSocket );
+ xmNewConnection->StartCallback();
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMAddConnection );
+ NAMESPACE_VOS(OGuard) aGuard2( *pMPostUserEvent );
+ nAddConnectionEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationManagerServerAcceptThread, AddConnection ) );
+ }
+ }
+ break;
+ case NAMESPACE_VOS(ISocketTypes::TResult_TimedOut):
+ delete pStreamSocket;
+ pStreamSocket = NULL;
+ break;
+ case NAMESPACE_VOS(ISocketTypes::TResult_Error):
+ delete pStreamSocket;
+ pStreamSocket = NULL;
+ break;
+
+ case NAMESPACE_VOS(ISocketTypes::TResult_Interrupted):
+ case NAMESPACE_VOS(ISocketTypes::TResult_InProgress):
+ break; // -Wall not handled...
+ }
+ }
+}
+
+
+IMPL_LINK( CommunicationManagerServerAcceptThread, AddConnection, void*, EMPTYARG )
+{
+ {
+ NAMESPACE_VOS(OGuard) aGuard( aMAddConnection );
+ nAddConnectionEventId = 0;
+ }
+ pMyServer->AddConnection( xmNewConnection );
+ xmNewConnection.Clear();
+ return 1;
+}
+
+
+#define GETSET(aVar, KeyName, Dafault) \
+ aVar = aConf.ReadKey(KeyName,"No Entry"); \
+ if ( aVar == "No Entry" ) \
+ { \
+ aVar = Dafault; \
+ aConf.WriteKey(KeyName, aVar); \
+ }
+
+
+CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( ByteString aHost, ULONG nPort, BOOL bUseMultiChannel )
+: CommunicationManagerClient( bUseMultiChannel )
+, aHostToTalk( aHost )
+, nPortToTalk( nPort )
+{
+}
+
+CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( BOOL bUseMultiChannel )
+: CommunicationManagerClient( bUseMultiChannel )
+, aHostToTalk( "" )
+, nPortToTalk( 0 )
+{
+}
+
+CommunicationManagerClientViaSocket::~CommunicationManagerClientViaSocket()
+{
+}
+
+