office-gobmx/automation/source/simplecm/simplecm.cxx
2011-08-23 14:05:22 +01:00

541 lines
16 KiB
C++
Raw Blame History

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* 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"
#define ENABLE_BYTESTRING_STREAM_OPERATORS
#include <tools/solar.h>
#include <automation/simplecm.hxx>
#include <osl/diagnose.h>
#include <automation/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( "%s\n", chars );
fflush( stdout );
}
}
#endif
CommunicationLink::CommunicationLink( CommunicationManager *pMan )
: pMyManager(pMan)
, pServiceData(NULL)
, nServiceProtocol( 0 )
, bIsInsideCallback( sal_False )
, nTotalBytes( 0 )
, maApplication("Undefined")
#if OSL_DEBUG_LEVEL > 1
, bFlag( sal_False )
, nSomething( 0 )
#endif
{
}
CommunicationLink::~CommunicationLink()
{
#if OSL_DEBUG_LEVEL > 1
if ( !bFlag ) // bFlag will be set if deletion is expected else we can set a breakpoint
bFlag = sal_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;
}
sal_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 );
sal_Bool bWasError = sal_False;
sal_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;
}
sal_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 )
{
maApplication = aApp;
}
SimpleCommunicationLinkViaSocket::SimpleCommunicationLinkViaSocket( CommunicationManager *pMan, osl::StreamSocket* pSocket )
: CommunicationLink( pMan )
, aCommunicationPartner()
, aMyName()
, pStreamSocket( pSocket )
, pReceiveStream( NULL )
, bIsRequestShutdownPending( sal_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( osl::StreamSocket* pSocket )
{
if ( pTCPIO )
pTCPIO->SetStreamSocket( pSocket );
pStreamSocket = pSocket;
}
sal_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 sal_True;
}
sal_Bool SimpleCommunicationLinkViaSocket::IsCommunicationError()
{
return !pStreamSocket;
}
ByteString SimpleCommunicationLinkViaSocket::GetCommunicationPartner( CM_NameType eType )
{
if ( pStreamSocket )
{
switch ( eType )
{
case CM_DOTTED:
{
rtl::OUString aDotted;
osl::SocketAddr* pPeerAdr = new osl::SocketAddr;
pStreamSocket->getPeerAddr( *pPeerAdr );
osl_getDottedInetAddrOfSocketAddr( pPeerAdr->getHandle(), &aDotted.pData);
delete pPeerAdr;
return ByteString( UniString(aDotted), RTL_TEXTENCODING_UTF8 );
}
//break;
case CM_FQDN:
{
if ( !aCommunicationPartner.Len() )
{
rtl::OUString aFQDN( pStreamSocket->getPeerHost());
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;
osl::SocketAddr* pPeerAdr = new osl::SocketAddr;
pStreamSocket->getPeerAddr( *pPeerAdr );
osl_getDottedInetAddrOfSocketAddr( pPeerAdr->getHandle(), &aDotted.pData);
delete pPeerAdr;
return ByteString( UniString(aDotted), RTL_TEXTENCODING_UTF8 );
}
//break;
case CM_FQDN:
{
if ( !aMyName.Len() )
{
rtl::OUString aFQDN(pStreamSocket->getLocalHost());
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;}
sal_Bool SimpleCommunicationLinkViaSocket::DoReceiveDataStream()
{
sal_Bool bWasError = sal_False;
void* pBuffer = NULL;
comm_UINT32 nLen;
bWasError = pPacketHandler->ReceiveData( 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, sal_True, nLen );
DBG_ASSERT( pReceiveStream, "Datastream is NULL");
}
return !bWasError;
}
void SimpleCommunicationLinkViaSocket::SetApplication( const ByteString& aApp )
{
CommunicationLink::SetApplication( aApp );
SvStream* pData = GetBestCommunicationStream();
*pData << aApp;
SendHandshake( CH_SetApplication, pData );
delete pData;
}
void SimpleCommunicationLinkViaSocket::SetNewPacketAsCurrent()
{
pServiceData = pReceiveStream;
nServiceProtocol = pPacketHandler->GetReceiveProtocol();
nServiceHeaderType = pPacketHandler->GetReceiveHeaderType();
}
sal_Bool SimpleCommunicationLinkViaSocket::SendHandshake( HandshakeType aHandshakeType, SvStream* pData )
{
sal_Bool bWasError;
if ( pData )
{
sal_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 = sal_True;
break;
case CH_ShutdownLink:
break;
case CH_SUPPORT_OPTIONS:
break;
case CH_SetApplication:
break;
default:
OSL_FAIL("Unknown HandshakeType");
}
}
return !bWasError;
}
CommunicationManager::CommunicationManager( sal_Bool bUseMultiChannel )
: nInfoType( CM_NONE )
, bIsCommunicationRunning( sal_False )
, maApplication("Unknown")
, bIsMultiChannel( bUseMultiChannel )
{
}
CommunicationManager::~CommunicationManager()
{
xLastNewLink.Clear();
}
sal_Bool CommunicationManager::StartCommunication( String aApp, String aParams )
{
(void) aApp; /* avoid warning about unused parameter */
(void) aParams; /* avoid warning about unused parameter */
return sal_False;
}
sal_Bool CommunicationManager::StartCommunication( ByteString aHost, sal_uLong nPort )
{
(void) aHost; /* avoid warning about unused parameter */
(void) nPort; /* avoid warning about unused parameter */
return sal_False;
}
ByteString CommunicationManager::GetMyName( CM_NameType )
{
rtl::OUString aHostname( osl::SocketAddr::getLocalHostname());
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 = sal_True;
pCL->SetApplication( GetApplication() );
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 )
{
OSL_FAIL( "Datastream is NULL" );
pCL->FinishCallback();
return;
}
if ( CH_Handshake == pCL->nServiceHeaderType )
{
SvStream *pData = pCL->GetServiceData();
sal_uInt16 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, sal_Bool bRunningLinks )
{
maApplication = aApp;
if ( bRunningLinks )
{
sal_uInt16 i;
for ( i = 0 ; i < GetCommunicationLinkCount() ; i++ )
GetCommunicationLink( i )->SetApplication( aApp );
}
}
sal_Bool CommonSocketFunctions::DoStartCommunication( CommunicationManager *pCM, ICommunicationManagerClient *pCMC, ByteString aHost, sal_uLong nPort )
{
osl::SocketAddr Addr( rtl::OUString( UniString( aHost, RTL_TEXTENCODING_UTF8 ) ), nPort );
osl::ConnectorSocket *pConnSocket;
TimeValue aTV;
aTV.Seconds = 10; // Warte 10 Sekunden
aTV.Nanosec = 0;
do
{
pConnSocket = new osl::ConnectorSocket();
pConnSocket->setOption( osl_Socket_OptionTcpNoDelay, 1 );
if ( pConnSocket->connect( Addr, &aTV ) == osl_Socket_Ok )
{
pConnSocket->setOption( osl_Socket_OptionTcpNoDelay, 1 );
pCM->CallConnectionOpened( CreateCommunicationLink( pCM, pConnSocket ) );
return sal_True;
}
else
delete pConnSocket;
} while ( pCMC->RetryConnect() );
return sal_False;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */