office-gobmx/automation/source/simplecm/simplecm.cxx

721 lines
21 KiB
C++
Raw Normal View History

/*************************************************************************
*
* $RCSfile: simplecm.cxx,v $
*
* $Revision: 1.2 $
*
* last change: $Author: rt $ $Date: 2005-06-21 19:07:16 $
*
* The Contents of this file are made available subject to the terms of
* either of the following licenses
*
* - GNU Lesser General Public License Version 2.1
* - Sun Industry Standards Source License Version 1.1
*
* Sun Microsystems Inc., October, 2000
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2000 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*
* Sun Industry Standards Source License Version 1.1
* =================================================
* The contents of this file are subject to the Sun Industry Standards
* Source License Version 1.1 (the "License"); You may not use this file
* except in compliance with the License. You may obtain a copy of the
* License at http://www.openoffice.org/license.html.
*
* Software provided under this License is provided on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
* WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
* MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
* See the License for the specific provisions governing your rights and
* obligations concerning the Software.
*
* The Initial Developer of the Original Code is: Sun Microsystems, Inc.
*
* Copyright: 2000 by Sun Microsystems, Inc.
*
* All Rights Reserved.
*
* Contributor(s): _______________________________________
*
*
************************************************************************/
#define ENABLE_BYTESTRING_STREAM_OPERATORS
#include <tools/solar.h>
#ifndef _SIMPLECM_HXX
#include "simplecm.hxx"
#endif
#include "commdefines.hxx"
#include "packethandler.hxx"
#include "tcpio.hxx"
#if OSL_DEBUG_LEVEL > 1
#include <stdio.h>
void debug_printf( const char *chars )
{
static BOOL bPrint = (getenv("DEBUG") != NULL);
if ( bPrint )
{
printf( chars );
fflush( stdout );
}
}
#endif
CommunicationLink::CommunicationLink( CommunicationManager *pMan )
: pMyManager(pMan)
, pServiceData(NULL)
, nServiceProtocol( 0 )
, bIsInsideCallback( FALSE )
, nTotalBytes( 0 )
, aApplication("Undefined")
, bFlag( FALSE )
, nSomething( 0 )
{
}
CommunicationLink::~CommunicationLink()
{
#if OSL_DEBUG_LEVEL > 1
if ( !bFlag ) // bFlag will be set if deletion is expected else we can set a breakpoint
bFlag = FALSE;
#endif
if ( pMyManager )
pMyManager->DestroyingLink( this );
}
void CommunicationLink::CallInfoMsg( InfoString aMsg )
{
if ( pMyManager )
pMyManager->InfoMsg( aMsg );
};
CM_InfoType CommunicationLink::GetInfoType()
{
if ( pMyManager )
return pMyManager->GetInfoType();
else
return CM_NO_TEXT;
}
IMPL_LINK( CommunicationLink, ConnectionClosed, void*, EMPTYARG )
{
if ( pMyManager )
pMyManager->CallConnectionClosed( this );
return 1;
}
IMPL_LINK( CommunicationLink, DataReceived, void*, EMPTYARG )
{
if ( pMyManager )
pMyManager->CallDataReceived( this );
return 1;
}
BOOL CommunicationLink::DoTransferDataStream( SvStream *pDataStream, CMProtocol nProtocol )
{
INFO_MSG( CByteString("S :").Append( GetCommunicationPartner( CM_FQDN ) ),
CByteString("Daten Senden:").Append( GetCommunicationPartner( CM_FQDN ) ),
CM_SEND, this );
BOOL bWasError = FALSE;
UINT32 nBuffer;
nBuffer = pDataStream->SeekRel(0) +1;
bWasError = pPacketHandler->TransferData( ((SvMemoryStream*)pDataStream)->GetData(), nBuffer, nProtocol ) != C_ERROR_NONE;
if ( bWasError )
{
INFO_MSG( CByteString("Send Failed:").Append( GetCommunicationPartner( CM_FQDN ) ),
CByteString( "Socket wird wegen Fehlers beim Senden geschlossen: ").Append( GetCommunicationPartner( CM_FQDN ) ),
CM_ERROR, this );
ShutdownCommunication();
}
return !bWasError;
}
BOOL CommunicationLink::TransferDataStream( SvStream *pDataStream, CMProtocol nProtocol )
{
aLastAccess = DateTime();
nTotalBytes += pDataStream->Seek( STREAM_SEEK_TO_END );
return DoTransferDataStream( pDataStream, nProtocol );
}
void CommunicationLink::SetApplication( const ByteString& aApp )
{
aApplication = aApp;
}
SimpleCommunicationLinkViaSocket::SimpleCommunicationLinkViaSocket( CommunicationManager *pMan, NAMESPACE_VOS(OStreamSocket) *pSocket )
: CommunicationLink( pMan )
, pStreamSocket( pSocket )
, pReceiveStream( NULL )
, aCommunicationPartner()
, aMyName()
, bIsRequestShutdownPending( FALSE )
{
pTCPIO = new TCPIO( pStreamSocket );
pPacketHandler = new PacketHandler( (ITransmiter*) pTCPIO, pTCPIO, pMyManager->IsMultiChannel() );
}
SimpleCommunicationLinkViaSocket::~SimpleCommunicationLinkViaSocket()
{
delete pPacketHandler;
pPacketHandler = NULL;
delete pTCPIO;
pTCPIO = NULL;
delete pStreamSocket;
pStreamSocket = NULL;
}
void SimpleCommunicationLinkViaSocket::SetStreamSocket( NAMESPACE_VOS(OStreamSocket)* pSocket )
{
if ( pTCPIO )
pTCPIO->SetStreamSocket( pSocket );
pStreamSocket = pSocket;
}
BOOL SimpleCommunicationLinkViaSocket::StopCommunication()
{
CommunicationLinkRef rHold(this); // avoid deleting this link before the end of the method
if ( !IsCommunicationError() ) // Meaning that the Communication is still runnung
{
#if OSL_DEBUG_LEVEL > 1
debug_printf("Sending REQUEST_ShutdownLink\n");
#endif
SendHandshake( CH_REQUEST_ShutdownLink );
}
WaitForShutdown();
return TRUE;
}
void SimpleCommunicationLinkViaSocket::SetFinalRecieveTimeout()
{
if ( !IsCommunicationError() )
{
TimeValue aTime = {30, 0}; // 30 seconds
pStreamSocket->setRecvTimeout( &aTime );
}
}
BOOL SimpleCommunicationLinkViaSocket::IsCommunicationError()
{
return !pStreamSocket;
}
ByteString SimpleCommunicationLinkViaSocket::GetCommunicationPartner( CM_NameType eType )
{
if ( pStreamSocket )
{
switch ( eType )
{
case CM_DOTTED:
{
rtl::OUString aDotted;
NAMESPACE_VOS(OSocketAddr) *pPeerAdr = new NAMESPACE_VOS(OSocketAddr);
pStreamSocket->getPeerAddr( *pPeerAdr );
((NAMESPACE_VOS(OInetSocketAddr*))pPeerAdr)->getDottedAddr( aDotted );
delete pPeerAdr;
return ByteString( UniString(aDotted), RTL_TEXTENCODING_UTF8 );
}
break;
case CM_FQDN:
{
if ( !aCommunicationPartner.Len() )
{
rtl::OUString aFQDN;
pStreamSocket->getPeerHost( aFQDN );
aCommunicationPartner = ByteString( UniString(aFQDN), RTL_TEXTENCODING_UTF8 );
}
return aCommunicationPartner;
}
break;
}
}
return CByteString( "Unknown" );
}
ByteString SimpleCommunicationLinkViaSocket::GetMyName( CM_NameType eType )
{
if ( pStreamSocket )
{
switch ( eType )
{
case CM_DOTTED:
{
rtl::OUString aDotted;
NAMESPACE_VOS(OSocketAddr) *pPeerAdr = new NAMESPACE_VOS(OSocketAddr);
pStreamSocket->getLocalAddr( *pPeerAdr );
((NAMESPACE_VOS(OInetSocketAddr*))pPeerAdr)->getDottedAddr( aDotted );
delete pPeerAdr;
return ByteString( UniString(aDotted), RTL_TEXTENCODING_UTF8 );
}
break;
case CM_FQDN:
{
if ( !aMyName.Len() )
{
rtl::OUString aFQDN;
pStreamSocket->getLocalHost( aFQDN );
aMyName = ByteString( UniString(aFQDN), RTL_TEXTENCODING_UTF8 );
}
return aMyName;
}
break;
}
}
return CByteString( "Error" );
}
SvStream* SimpleCommunicationLinkViaSocket::GetBestCommunicationStream()
{
SvStream* pStream = new SvMemoryStream;
// pStream->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
return pStream;
}
#define READ_SOCKET( pBuffer, nLength )\
if ( !bWasError )\
{bWasError |= pTCPIO->ReceiveBytes( pBuffer, nLength ) != C_ERROR_NONE;}
#define READ_SOCKET_LEN( pBuffer, nLength, nTotal )\
READ_SOCKET( pBuffer, nLength );\
if ( !bWasError )\
{nTotal += nLength;}
BOOL SimpleCommunicationLinkViaSocket::DoReceiveDataStream()
{
BOOL bWasError = FALSE;
char* pBuffer = NULL;
ULONG nLen;
bWasError = pPacketHandler->ReceiveData( (void* &)pBuffer, nLen ) != C_ERROR_NONE;
if ( !bWasError )
{
pReceiveStream = GetBestCommunicationStream();
DBG_ASSERT( pReceiveStream->IsA() == ID_MEMORYSTREAM, "CommunicationStream is not an SvMemoryStream. Communication has to be reimplemented here!")
if ( pReceiveStream->IsA() == ID_MEMORYSTREAM )
((SvMemoryStream*)pReceiveStream)->SetBuffer( pBuffer, nLen, TRUE, nLen );
DBG_ASSERT( pReceiveStream, "Datastream is NULL")
}
return !bWasError;
}
void SimpleCommunicationLinkViaSocket::SetApplication( const ByteString& aApp )
{
CommunicationLink::SetApplication( aApp );
SvStream* pData = GetBestCommunicationStream();
*pData << aApplication;
SendHandshake( CH_SetApplication, pData );
delete pData;
}
void SimpleCommunicationLinkViaSocket::SetNewPacketAsCurrent()
{
pServiceData = pReceiveStream;
nServiceProtocol = pPacketHandler->GetReceiveProtocol();
nServiceHeaderType = pPacketHandler->GetReceiveHeaderType();
}
BOOL SimpleCommunicationLinkViaSocket::SendHandshake( HandshakeType aHandshakeType, SvStream* pData )
{
BOOL bWasError;
if ( pData )
{
UINT32 nBuffer;
nBuffer = pData->Seek( STREAM_SEEK_TO_END );
bWasError = !pPacketHandler->SendHandshake( aHandshakeType, ((SvMemoryStream*)pData)->GetData(), nBuffer );
}
else
bWasError = !pPacketHandler->SendHandshake( aHandshakeType );
if ( bWasError )
{
INFO_MSG( CByteString("Send Failed:").Append( GetCommunicationPartner( CM_FQDN ) ),
CByteString( "Socket wird wegen Fehlers beim Senden geschlossen: ").Append( GetCommunicationPartner( CM_FQDN ) ),
CM_ERROR, this );
ShutdownCommunication();
}
else
{ // set new status
switch ( aHandshakeType )
{
case CH_REQUEST_HandshakeAlive:
break;
case CH_RESPONSE_HandshakeAlive:
break;
case CH_REQUEST_ShutdownLink:
bIsRequestShutdownPending = TRUE;
break;
case CH_ShutdownLink:
break;
case CH_SUPPORT_OPTIONS:
break;
case CH_SetApplication:
break;
default:
DBG_ERROR("Unknown HandshakeType");
}
}
return !bWasError;
}
SimpleCommunicationLinkViaSocketWithReceiveCallbacks::SimpleCommunicationLinkViaSocketWithReceiveCallbacks( CommunicationManager *pMan, NAMESPACE_VOS(OStreamSocket) *pSocket )
: SimpleCommunicationLinkViaSocket( pMan, pSocket )
{
}
SimpleCommunicationLinkViaSocketWithReceiveCallbacks::~SimpleCommunicationLinkViaSocketWithReceiveCallbacks()
{
if ( pMyManager && pMyManager->IsLinkValid( this ) && !bIsRequestShutdownPending )
StopCommunication();
}
void SimpleCommunicationLinkViaSocketWithReceiveCallbacks::WaitForShutdown()
{
CommunicationLinkRef rHold(this); // avoid deleting this link before the end of the method
SetFinalRecieveTimeout();
while ( pMyManager && !IsCommunicationError() )
ReceiveDataStream();
}
BOOL SimpleCommunicationLinkViaSocketWithReceiveCallbacks::ReceiveDataStream()
{
if ( DoReceiveDataStream() )
{
SetNewPacketAsCurrent();
StartCallback();
DataReceived();
return TRUE;
}
else
{
StartCallback();
ShutdownCommunication();
return FALSE;
}
}
BOOL SimpleCommunicationLinkViaSocketWithReceiveCallbacks::ShutdownCommunication()
{
if ( GetStreamSocket() )
GetStreamSocket()->shutdown();
if ( GetStreamSocket() )
GetStreamSocket()->close();
NAMESPACE_VOS(OStreamSocket) *pTempSocket = GetStreamSocket();
SetStreamSocket( NULL );
delete pTempSocket;
ConnectionClosed();
return TRUE;
}
CommunicationManager::CommunicationManager( BOOL bUseMultiChannel )
: bIsCommunicationRunning( FALSE )
, nInfoType( CM_NONE )
, bIsMultiChannel( bUseMultiChannel )
, aApplication("Unknown")
{
}
CommunicationManager::~CommunicationManager()
{
xLastNewLink.Clear();
}
ByteString CommunicationManager::GetMyName( CM_NameType eType )
{
rtl::OUString aHostname;
NAMESPACE_VOS(OSocketAddr)::getLocalHostname( aHostname );
return ByteString( UniString(aHostname), RTL_TEXTENCODING_UTF8 );
}
void CommunicationManager::CallConnectionOpened( CommunicationLink* pCL )
{
pCL->StartCallback(); // Sollte bereits vor dem Aufruf gerufen werden
pCL->aStart = DateTime();
pCL->aLastAccess = pCL->aStart;
bIsCommunicationRunning = TRUE;
pCL->SetApplication( aApplication );
xLastNewLink = pCL;
INFO_MSG( CByteString("C+:").Append( pCL->GetCommunicationPartner( CM_FQDN ) ),
CByteString("Verbindung aufgebaut: ").Append( pCL->GetCommunicationPartner( CM_FQDN ) ),
CM_OPEN, pCL );
ConnectionOpened( pCL );
pCL->FinishCallback();
}
void CommunicationManager::CallConnectionClosed( CommunicationLink* pCL )
{
pCL->StartCallback(); // Sollte bereits vor dem Aufruf gerufen werden
pCL->aLastAccess = DateTime();
INFO_MSG( CByteString("C-:").Append( pCL->GetCommunicationPartner( CM_FQDN ) ),
CByteString("Verbindung abgebrochen: ").Append( pCL->GetCommunicationPartner( CM_FQDN ) ),
CM_CLOSE, pCL );
ConnectionClosed( pCL );
if ( xLastNewLink == pCL )
xLastNewLink.Clear();
pCL->FinishCallback();
// delete pCL;
}
void CommunicationManager::CallDataReceived( CommunicationLink* pCL )
{
pCL->StartCallback(); // Sollte bereits vor dem Aufruf gerufen werden
pCL->aLastAccess = DateTime();
CommunicationLinkRef rHold(pCL); // H<>lt den Zeiger bis zum Ende des calls
// should be impossible but happens for mysterious reasons
if ( !pCL->pServiceData )
{
DBG_ERROR( "Datastream is NULL" )
pCL->FinishCallback();
return;
}
if ( CH_Handshake == pCL->nServiceHeaderType )
{
SvStream *pData = pCL->GetServiceData();
USHORT nType;
pData->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); // Unfortulately it is written this way :((
*pData >> nType;
pData->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN );
switch ( nType )
{
case CH_REQUEST_HandshakeAlive:
{
pCL->SendHandshake( CH_RESPONSE_HandshakeAlive );
}
break;
case CH_REQUEST_ShutdownLink:
{
#if OSL_DEBUG_LEVEL > 1
debug_printf("Sending ShutdownLink\n");
#endif
pCL->SendHandshake( CH_ShutdownLink );
}
break;
case CH_ShutdownLink:
{
#if OSL_DEBUG_LEVEL > 1
debug_printf("Executing ShutdownLink\n");
#endif
pCL->ShutdownCommunication();
}
break;
case CH_SetApplication:
{
ByteString aApplication;
*pData >> aApplication;
pCL->CommunicationLink::SetApplication( aApplication );
#if OSL_DEBUG_LEVEL > 1
debug_printf( "Setting Application to " );
debug_printf( aApplication.GetBuffer() );
debug_printf( "\n" );
#endif
}
break;
#if OSL_DEBUG_LEVEL > 1
default:
{
debug_printf("Unknown Handshake received\n");
}
#endif
}
delete pData;
}
else
{
if ( pCL->pServiceData )
{
pCL->nTotalBytes += pCL->pServiceData->Seek( STREAM_SEEK_TO_END );
pCL->pServiceData->Seek( STREAM_SEEK_TO_BEGIN );
}
INFO_MSG( CByteString("D :").Append( pCL->GetCommunicationPartner( CM_FQDN ) ),
CByteString("Daten Empfangen:").Append( pCL->GetCommunicationPartner( CM_FQDN ) ),
CM_RECEIVE, pCL );
DataReceived( pCL );
}
delete pCL->GetServiceData();
pCL->FinishCallback();
}
void CommunicationManager::CallInfoMsg( InfoString aMsg )
{
// Hier wird es wohl kein Housekeeping geben
InfoMsg( aMsg );
}
void CommunicationManager::SetApplication( const ByteString& aApp, BOOL bRunningLinks )
{
aApplication = aApp;
if ( bRunningLinks )
{
USHORT i;
for ( i = 0 ; i < GetCommunicationLinkCount() ; i++ )
GetCommunicationLink( i )->SetApplication( aApp );
}
}
SingleCommunicationManager::SingleCommunicationManager( BOOL bUseMultiChannel )
: CommunicationManager( bUseMultiChannel )
{
xActiveLink = NULL;
pInactiveLink = NULL;
}
SingleCommunicationManager::~SingleCommunicationManager()
{
StopCommunication();
if ( pInactiveLink )
pInactiveLink->InvalidateManager();
}
BOOL SingleCommunicationManager::StopCommunication()
{
if ( xActiveLink.Is() )
{
BOOL bSuccess = xActiveLink->StopCommunication();
if ( pInactiveLink )
pInactiveLink->InvalidateManager();
pInactiveLink = xActiveLink;
xActiveLink.Clear();
return bSuccess;
}
return TRUE;
}
BOOL SingleCommunicationManager::IsLinkValid( CommunicationLink* pCL )
{
return &xActiveLink == pCL;
}
USHORT SingleCommunicationManager::GetCommunicationLinkCount()
{
return IsCommunicationRunning()?1:0;
}
CommunicationLinkRef SingleCommunicationManager::GetCommunicationLink( USHORT nNr )
{
return xActiveLink;
}
void SingleCommunicationManager::CallConnectionOpened( CommunicationLink* pCL )
{
DBG_ASSERT( !xActiveLink.Is(), "Es ist bereits ein CommunicationLink aktiv");
if ( xActiveLink.Is() )
{
if ( pInactiveLink )
pInactiveLink->InvalidateManager();
pInactiveLink = xActiveLink;
xActiveLink->StopCommunication(); // Den alten Link brutal abw<62>rgen
}
xActiveLink = pCL;
CommunicationManager::CallConnectionOpened( pCL );
}
void SingleCommunicationManager::CallConnectionClosed( CommunicationLink* pCL )
{
CommunicationManager::CallConnectionClosed( pCL );
DBG_ASSERT( pCL == xActiveLink, "SingleCommunicationManager::CallConnectionClosed mit fremdem Link");
if ( pInactiveLink )
pInactiveLink->InvalidateManager();
pInactiveLink = xActiveLink;
xActiveLink.Clear();
bIsCommunicationRunning = FALSE;
}
void SingleCommunicationManager::DestroyingLink( CommunicationLink *pCL )
{
pInactiveLink = NULL;
pCL->InvalidateManager();
}
SingleCommunicationManagerClientViaSocket::SingleCommunicationManagerClientViaSocket( ByteString aHost, ULONG nPort, BOOL bUseMultiChannel )
: SingleCommunicationManager( bUseMultiChannel )
, aHostToTalk( aHost )
, nPortToTalk( nPort )
{
}
SingleCommunicationManagerClientViaSocket::SingleCommunicationManagerClientViaSocket( BOOL bUseMultiChannel )
: SingleCommunicationManager( bUseMultiChannel )
, aHostToTalk()
, nPortToTalk( 0 )
{
}
BOOL CommonSocketFunctions::DoStartCommunication( CommunicationManager *pCM, ICommunicationManagerClient *pCMC, ByteString aHost, ULONG nPort )
{
NAMESPACE_VOS(OInetSocketAddr) Addr;
NAMESPACE_VOS(OConnectorSocket) *pConnSocket;
Addr.setAddr( rtl::OUString( UniString( aHost, RTL_TEXTENCODING_UTF8 ) ) );
Addr.setPort( nPort );
TimeValue aTV;
aTV.Seconds = 10; // Warte 10 Sekunden
aTV.Nanosec = 0;
do
{
pConnSocket = new NAMESPACE_VOS(OConnectorSocket)();
pConnSocket->setTcpNoDelay( 1 );
if ( pConnSocket->connect( Addr, &aTV ) == NAMESPACE_VOS(ISocketTypes::TResult_Ok) )
{
pConnSocket->setTcpNoDelay( 1 );
pCM->CallConnectionOpened( CreateCommunicationLink( pCM, pConnSocket ) );
return TRUE;
}
else
delete pConnSocket;
} while ( pCMC->RetryConnect() );
return FALSE;
}