1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: simplecm.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_automation.hxx"
35 #define ENABLE_BYTESTRING_STREAM_OPERATORS
36 #include <tools/solar.h>
37 #include <automation/simplecm.hxx>
39 #include <automation/commdefines.hxx>
40 #include "packethandler.hxx"
43 #if OSL_DEBUG_LEVEL > 1
45 void debug_printf( const char *chars
)
47 static BOOL bPrint
= (getenv("DEBUG") != NULL
);
56 CommunicationLink::CommunicationLink( CommunicationManager
*pMan
)
59 , nServiceProtocol( 0 )
60 , bIsInsideCallback( FALSE
)
62 , maApplication("Undefined")
63 #if OSL_DEBUG_LEVEL > 1
70 CommunicationLink::~CommunicationLink()
72 #if OSL_DEBUG_LEVEL > 1
73 if ( !bFlag
) // bFlag will be set if deletion is expected else we can set a breakpoint
77 pMyManager
->DestroyingLink( this );
80 void CommunicationLink::CallInfoMsg( InfoString aMsg
)
83 pMyManager
->InfoMsg( aMsg
);
86 CM_InfoType
CommunicationLink::GetInfoType()
89 return pMyManager
->GetInfoType();
94 IMPL_LINK( CommunicationLink
, ConnectionClosed
, void*, EMPTYARG
)
97 pMyManager
->CallConnectionClosed( this );
101 IMPL_LINK( CommunicationLink
, DataReceived
, void*, EMPTYARG
)
104 pMyManager
->CallDataReceived( this );
108 BOOL
CommunicationLink::DoTransferDataStream( SvStream
*pDataStream
, CMProtocol nProtocol
)
110 INFO_MSG( CByteString("S :").Append( GetCommunicationPartner( CM_FQDN
) ),
111 CByteString("Daten Senden:").Append( GetCommunicationPartner( CM_FQDN
) ),
113 BOOL bWasError
= FALSE
;
116 nBuffer
= pDataStream
->SeekRel(0) +1;
117 bWasError
= pPacketHandler
->TransferData( ((SvMemoryStream
*)pDataStream
)->GetData(), nBuffer
, nProtocol
) != C_ERROR_NONE
;
121 INFO_MSG( CByteString("Send Failed:").Append( GetCommunicationPartner( CM_FQDN
) ),
122 CByteString( "Socket wird wegen Fehlers beim Senden geschlossen: ").Append( GetCommunicationPartner( CM_FQDN
) ),
124 ShutdownCommunication();
129 BOOL
CommunicationLink::TransferDataStream( SvStream
*pDataStream
, CMProtocol nProtocol
)
131 aLastAccess
= DateTime();
132 nTotalBytes
+= pDataStream
->Seek( STREAM_SEEK_TO_END
);
133 return DoTransferDataStream( pDataStream
, nProtocol
);
136 void CommunicationLink::SetApplication( const ByteString
& aApp
)
138 maApplication
= aApp
;
142 SimpleCommunicationLinkViaSocket::SimpleCommunicationLinkViaSocket( CommunicationManager
*pMan
, NAMESPACE_VOS(OStreamSocket
) *pSocket
)
143 : CommunicationLink( pMan
)
144 , aCommunicationPartner()
146 , pStreamSocket( pSocket
)
147 , pReceiveStream( NULL
)
148 , bIsRequestShutdownPending( FALSE
)
150 pTCPIO
= new TCPIO( pStreamSocket
);
151 pPacketHandler
= new PacketHandler( (ITransmiter
*) pTCPIO
, pTCPIO
, pMyManager
->IsMultiChannel() );
154 SimpleCommunicationLinkViaSocket::~SimpleCommunicationLinkViaSocket()
156 delete pPacketHandler
;
157 pPacketHandler
= NULL
;
160 delete pStreamSocket
;
161 pStreamSocket
= NULL
;
164 void SimpleCommunicationLinkViaSocket::SetStreamSocket( NAMESPACE_VOS(OStreamSocket
)* pSocket
)
167 pTCPIO
->SetStreamSocket( pSocket
);
168 pStreamSocket
= pSocket
;
171 BOOL
SimpleCommunicationLinkViaSocket::StopCommunication()
173 CommunicationLinkRef
rHold(this); // avoid deleting this link before the end of the method
174 if ( !IsCommunicationError() ) // Meaning that the Communication is still runnung
176 #if OSL_DEBUG_LEVEL > 1
177 debug_printf("Sending REQUEST_ShutdownLink\n");
179 SendHandshake( CH_REQUEST_ShutdownLink
);
185 void SimpleCommunicationLinkViaSocket::SetFinalRecieveTimeout()
187 if ( !IsCommunicationError() )
189 TimeValue aTime
= {30, 0}; // 30 seconds
190 pStreamSocket
->setRecvTimeout( &aTime
);
194 BOOL
SimpleCommunicationLinkViaSocket::IsCommunicationError()
196 return !pStreamSocket
;
199 ByteString
SimpleCommunicationLinkViaSocket::GetCommunicationPartner( CM_NameType eType
)
207 rtl::OUString aDotted
;
208 NAMESPACE_VOS(OSocketAddr
) *pPeerAdr
= new NAMESPACE_VOS(OSocketAddr
);
209 pStreamSocket
->getPeerAddr( *pPeerAdr
);
210 ((NAMESPACE_VOS(OInetSocketAddr
*))pPeerAdr
)->getDottedAddr( aDotted
);
212 return ByteString( UniString(aDotted
), RTL_TEXTENCODING_UTF8
);
217 if ( !aCommunicationPartner
.Len() )
220 pStreamSocket
->getPeerHost( aFQDN
);
221 aCommunicationPartner
= ByteString( UniString(aFQDN
), RTL_TEXTENCODING_UTF8
);
223 return aCommunicationPartner
;
228 return CByteString( "Unknown" );
231 ByteString
SimpleCommunicationLinkViaSocket::GetMyName( CM_NameType eType
)
239 rtl::OUString aDotted
;
240 NAMESPACE_VOS(OSocketAddr
) *pPeerAdr
= new NAMESPACE_VOS(OSocketAddr
);
241 pStreamSocket
->getLocalAddr( *pPeerAdr
);
242 ((NAMESPACE_VOS(OInetSocketAddr
*))pPeerAdr
)->getDottedAddr( aDotted
);
244 return ByteString( UniString(aDotted
), RTL_TEXTENCODING_UTF8
);
249 if ( !aMyName
.Len() )
252 pStreamSocket
->getLocalHost( aFQDN
);
253 aMyName
= ByteString( UniString(aFQDN
), RTL_TEXTENCODING_UTF8
);
260 return CByteString( "Error" );
263 SvStream
* SimpleCommunicationLinkViaSocket::GetBestCommunicationStream()
265 SvStream
* pStream
= new SvMemoryStream
;
266 // pStream->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN );
270 #define READ_SOCKET( pBuffer, nLength )\
272 {bWasError |= pTCPIO->ReceiveBytes( pBuffer, nLength ) != C_ERROR_NONE;}
274 #define READ_SOCKET_LEN( pBuffer, nLength, nTotal )\
275 READ_SOCKET( pBuffer, nLength );\
279 BOOL
SimpleCommunicationLinkViaSocket::DoReceiveDataStream()
281 BOOL bWasError
= FALSE
;
282 char* pBuffer
= NULL
;
284 bWasError
= pPacketHandler
->ReceiveData( (void* &)pBuffer
, nLen
) != C_ERROR_NONE
;
287 pReceiveStream
= GetBestCommunicationStream();
288 DBG_ASSERT( pReceiveStream
->IsA() == ID_MEMORYSTREAM
, "CommunicationStream is not an SvMemoryStream. Communication has to be reimplemented here!");
289 if ( pReceiveStream
->IsA() == ID_MEMORYSTREAM
)
290 ((SvMemoryStream
*)pReceiveStream
)->SetBuffer( pBuffer
, nLen
, TRUE
, nLen
);
291 DBG_ASSERT( pReceiveStream
, "Datastream is NULL");
297 void SimpleCommunicationLinkViaSocket::SetApplication( const ByteString
& aApp
)
299 CommunicationLink::SetApplication( aApp
);
300 SvStream
* pData
= GetBestCommunicationStream();
302 SendHandshake( CH_SetApplication
, pData
);
306 void SimpleCommunicationLinkViaSocket::SetNewPacketAsCurrent()
308 pServiceData
= pReceiveStream
;
309 nServiceProtocol
= pPacketHandler
->GetReceiveProtocol();
310 nServiceHeaderType
= pPacketHandler
->GetReceiveHeaderType();
313 BOOL
SimpleCommunicationLinkViaSocket::SendHandshake( HandshakeType aHandshakeType
, SvStream
* pData
)
320 nBuffer
= pData
->Seek( STREAM_SEEK_TO_END
);
321 bWasError
= !pPacketHandler
->SendHandshake( aHandshakeType
, ((SvMemoryStream
*)pData
)->GetData(), nBuffer
);
324 bWasError
= !pPacketHandler
->SendHandshake( aHandshakeType
);
329 INFO_MSG( CByteString("Send Failed:").Append( GetCommunicationPartner( CM_FQDN
) ),
330 CByteString( "Socket wird wegen Fehlers beim Senden geschlossen: ").Append( GetCommunicationPartner( CM_FQDN
) ),
332 ShutdownCommunication();
336 switch ( aHandshakeType
)
338 case CH_REQUEST_HandshakeAlive
:
340 case CH_RESPONSE_HandshakeAlive
:
342 case CH_REQUEST_ShutdownLink
:
343 bIsRequestShutdownPending
= TRUE
;
345 case CH_ShutdownLink
:
347 case CH_SUPPORT_OPTIONS
:
349 case CH_SetApplication
:
352 DBG_ERROR("Unknown HandshakeType");
358 SimpleCommunicationLinkViaSocketWithReceiveCallbacks::SimpleCommunicationLinkViaSocketWithReceiveCallbacks( CommunicationManager
*pMan
, NAMESPACE_VOS(OStreamSocket
) *pSocket
)
359 : SimpleCommunicationLinkViaSocket( pMan
, pSocket
)
363 SimpleCommunicationLinkViaSocketWithReceiveCallbacks::~SimpleCommunicationLinkViaSocketWithReceiveCallbacks()
365 if ( pMyManager
&& pMyManager
->IsLinkValid( this ) && !bIsRequestShutdownPending
)
369 void SimpleCommunicationLinkViaSocketWithReceiveCallbacks::WaitForShutdown()
371 CommunicationLinkRef
rHold(this); // avoid deleting this link before the end of the method
372 SetFinalRecieveTimeout();
373 while ( pMyManager
&& !IsCommunicationError() )
377 BOOL
SimpleCommunicationLinkViaSocketWithReceiveCallbacks::ReceiveDataStream()
379 if ( DoReceiveDataStream() )
381 SetNewPacketAsCurrent();
389 ShutdownCommunication();
394 BOOL
SimpleCommunicationLinkViaSocketWithReceiveCallbacks::ShutdownCommunication()
396 if ( GetStreamSocket() )
397 GetStreamSocket()->shutdown();
399 if ( GetStreamSocket() )
400 GetStreamSocket()->close();
402 NAMESPACE_VOS(OStreamSocket
) *pTempSocket
= GetStreamSocket();
403 SetStreamSocket( NULL
);
413 CommunicationManager::CommunicationManager( BOOL bUseMultiChannel
)
414 : nInfoType( CM_NONE
)
415 , bIsCommunicationRunning( FALSE
)
416 , maApplication("Unknown")
417 , bIsMultiChannel( bUseMultiChannel
)
421 CommunicationManager::~CommunicationManager()
423 xLastNewLink
.Clear();
426 BOOL
CommunicationManager::StartCommunication( String aApp
, String aParams
)
428 (void) aApp
; /* avoid warning about unused parameter */
429 (void) aParams
; /* avoid warning about unused parameter */
433 BOOL
CommunicationManager::StartCommunication( ByteString aHost
, ULONG nPort
)
435 (void) aHost
; /* avoid warning about unused parameter */
436 (void) nPort
; /* avoid warning about unused parameter */
440 ByteString
CommunicationManager::GetMyName( CM_NameType
)
442 rtl::OUString aHostname
;
443 NAMESPACE_VOS(OSocketAddr
)::getLocalHostname( aHostname
);
444 return ByteString( UniString(aHostname
), RTL_TEXTENCODING_UTF8
);
447 void CommunicationManager::CallConnectionOpened( CommunicationLink
* pCL
)
449 pCL
->StartCallback(); // Sollte bereits vor dem Aufruf gerufen werden
450 pCL
->aStart
= DateTime();
451 pCL
->aLastAccess
= pCL
->aStart
;
452 bIsCommunicationRunning
= TRUE
;
453 pCL
->SetApplication( GetApplication() );
457 INFO_MSG( CByteString("C+:").Append( pCL
->GetCommunicationPartner( CM_FQDN
) ),
458 CByteString("Verbindung aufgebaut: ").Append( pCL
->GetCommunicationPartner( CM_FQDN
) ),
460 ConnectionOpened( pCL
);
461 pCL
->FinishCallback();
464 void CommunicationManager::CallConnectionClosed( CommunicationLink
* pCL
)
466 pCL
->StartCallback(); // Sollte bereits vor dem Aufruf gerufen werden
467 pCL
->aLastAccess
= DateTime();
469 INFO_MSG( CByteString("C-:").Append( pCL
->GetCommunicationPartner( CM_FQDN
) ),
470 CByteString("Verbindung abgebrochen: ").Append( pCL
->GetCommunicationPartner( CM_FQDN
) ),
472 ConnectionClosed( pCL
);
474 if ( xLastNewLink
== pCL
)
475 xLastNewLink
.Clear();
477 pCL
->FinishCallback();
481 void CommunicationManager::CallDataReceived( CommunicationLink
* pCL
)
483 pCL
->StartCallback(); // Sollte bereits vor dem Aufruf gerufen werden
484 pCL
->aLastAccess
= DateTime();
485 CommunicationLinkRef
rHold(pCL
); // Hält den Zeiger bis zum Ende des calls
487 // should be impossible but happens for mysterious reasons
488 if ( !pCL
->pServiceData
)
490 DBG_ERROR( "Datastream is NULL" );
491 pCL
->FinishCallback();
496 if ( CH_Handshake
== pCL
->nServiceHeaderType
)
498 SvStream
*pData
= pCL
->GetServiceData();
500 pData
->SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN
); // Unfortulately it is written this way :((
502 pData
->SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN
);
505 case CH_REQUEST_HandshakeAlive
:
507 pCL
->SendHandshake( CH_RESPONSE_HandshakeAlive
);
510 case CH_REQUEST_ShutdownLink
:
512 #if OSL_DEBUG_LEVEL > 1
513 debug_printf("Sending ShutdownLink\n");
515 pCL
->SendHandshake( CH_ShutdownLink
);
518 case CH_ShutdownLink
:
520 #if OSL_DEBUG_LEVEL > 1
521 debug_printf("Executing ShutdownLink\n");
523 pCL
->ShutdownCommunication();
526 case CH_SetApplication
:
528 ByteString aApplication
;
529 *pData
>> aApplication
;
530 pCL
->CommunicationLink::SetApplication( aApplication
);
531 #if OSL_DEBUG_LEVEL > 1
532 debug_printf( "Setting Application to " );
533 debug_printf( aApplication
.GetBuffer() );
534 debug_printf( "\n" );
539 #if OSL_DEBUG_LEVEL > 1
542 debug_printf("Unknown Handshake received\n");
550 if ( pCL
->pServiceData
)
552 pCL
->nTotalBytes
+= pCL
->pServiceData
->Seek( STREAM_SEEK_TO_END
);
553 pCL
->pServiceData
->Seek( STREAM_SEEK_TO_BEGIN
);
556 INFO_MSG( CByteString("D :").Append( pCL
->GetCommunicationPartner( CM_FQDN
) ),
557 CByteString("Daten Empfangen:").Append( pCL
->GetCommunicationPartner( CM_FQDN
) ),
561 delete pCL
->GetServiceData();
562 pCL
->FinishCallback();
565 void CommunicationManager::CallInfoMsg( InfoString aMsg
)
567 // Hier wird es wohl kein Housekeeping geben
571 void CommunicationManager::SetApplication( const ByteString
& aApp
, BOOL bRunningLinks
)
573 maApplication
= aApp
;
577 for ( i
= 0 ; i
< GetCommunicationLinkCount() ; i
++ )
578 GetCommunicationLink( i
)->SetApplication( aApp
);
584 SingleCommunicationManager::SingleCommunicationManager( BOOL bUseMultiChannel
)
585 : CommunicationManager( bUseMultiChannel
)
588 pInactiveLink
= NULL
;
591 SingleCommunicationManager::~SingleCommunicationManager()
595 pInactiveLink
->InvalidateManager();
598 BOOL
SingleCommunicationManager::StopCommunication()
600 if ( xActiveLink
.Is() )
602 BOOL bSuccess
= xActiveLink
->StopCommunication();
604 pInactiveLink
->InvalidateManager();
605 pInactiveLink
= xActiveLink
;
612 BOOL
SingleCommunicationManager::IsLinkValid( CommunicationLink
* pCL
)
614 return &xActiveLink
== pCL
;
617 USHORT
SingleCommunicationManager::GetCommunicationLinkCount()
619 return IsCommunicationRunning()?1:0;
622 CommunicationLinkRef
SingleCommunicationManager::GetCommunicationLink( USHORT
)
627 void SingleCommunicationManager::CallConnectionOpened( CommunicationLink
* pCL
)
629 DBG_ASSERT( !xActiveLink
.Is(), "Es ist bereits ein CommunicationLink aktiv");
630 if ( xActiveLink
.Is() )
633 pInactiveLink
->InvalidateManager();
634 pInactiveLink
= xActiveLink
;
635 xActiveLink
->StopCommunication(); // Den alten Link brutal abwürgen
638 CommunicationManager::CallConnectionOpened( pCL
);
641 void SingleCommunicationManager::CallConnectionClosed( CommunicationLink
* pCL
)
643 CommunicationManager::CallConnectionClosed( pCL
);
645 DBG_ASSERT( pCL
== xActiveLink
, "SingleCommunicationManager::CallConnectionClosed mit fremdem Link");
647 pInactiveLink
->InvalidateManager();
648 pInactiveLink
= xActiveLink
;
650 bIsCommunicationRunning
= FALSE
;
653 void SingleCommunicationManager::DestroyingLink( CommunicationLink
*pCL
)
655 pInactiveLink
= NULL
;
656 pCL
->InvalidateManager();
660 SingleCommunicationManagerClientViaSocket::SingleCommunicationManagerClientViaSocket( ByteString aHost
, ULONG nPort
, BOOL bUseMultiChannel
)
661 : SingleCommunicationManager( bUseMultiChannel
)
662 , aHostToTalk( aHost
)
663 , nPortToTalk( nPort
)
668 SingleCommunicationManagerClientViaSocket::SingleCommunicationManagerClientViaSocket( BOOL bUseMultiChannel
)
669 : SingleCommunicationManager( bUseMultiChannel
)
676 BOOL
CommonSocketFunctions::DoStartCommunication( CommunicationManager
*pCM
, ICommunicationManagerClient
*pCMC
, ByteString aHost
, ULONG nPort
)
678 NAMESPACE_VOS(OInetSocketAddr
) Addr
;
679 NAMESPACE_VOS(OConnectorSocket
) *pConnSocket
;
681 Addr
.setAddr( rtl::OUString( UniString( aHost
, RTL_TEXTENCODING_UTF8
) ) );
682 Addr
.setPort( nPort
);
685 aTV
.Seconds
= 10; // Warte 10 Sekunden
689 pConnSocket
= new NAMESPACE_VOS(OConnectorSocket
)();
690 pConnSocket
->setTcpNoDelay( 1 );
691 if ( pConnSocket
->connect( Addr
, &aTV
) == NAMESPACE_VOS(ISocketTypes::TResult_Ok
) )
693 pConnSocket
->setTcpNoDelay( 1 );
695 pCM
->CallConnectionOpened( CreateCommunicationLink( pCM
, pConnSocket
) );
701 } while ( pCMC
->RetryConnect() );