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: communi.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"
34 #if OSL_DEBUG_LEVEL > 1
35 #define DEBUGPRINTF(x) { printf(x); fflush( stdout ); }
37 #define DEBUGPRINTF(x)
39 #include <tools/debug.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vos/socket.hxx>
42 #include <tools/stream.hxx>
43 #include <vcl/timer.hxx>
44 #include <tools/fsys.hxx>
46 #include <automation/communi.hxx>
49 /* Um den Destruktor protected zu machen wurde unten das delete entfernt.
50 Die Methode wird ohnehin hucht benutzt.
51 // delete *((AE*)pData+n);
54 #undef SV_IMPL_PTRARR_SORT
55 #define SV_IMPL_PTRARR_SORT( nm,AE )\
56 _SV_IMPL_SORTAR_ALG( nm,AE )\
57 void nm::DeleteAndDestroy( USHORT nP, USHORT nL ) { \
59 DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );\
60 for( USHORT n=nP; n < nP + nL; n++ ) \
61 DBG_ERROR("Das Element der Liste wurde nicht gelöscht"); \
62 SvPtrarr::Remove( nP, nL ); \
65 _SV_SEEK_PTR( nm, AE )
70 SV_IMPL_PTRARR_SORT( CommunicationLinkList
, CommunicationLink
* );
72 NAMESPACE_VOS(OMutex
) *pMPostUserEvent
=NULL
; // Notwendig, da nicht threadfest
74 CommunicationLinkViaSocket::CommunicationLinkViaSocket( CommunicationManager
*pMan
, NAMESPACE_VOS(OStreamSocket
) *pSocket
)
75 : SimpleCommunicationLinkViaSocket( pMan
, pSocket
)
76 , nConnectionClosedEventId( 0 )
77 , nDataReceivedEventId( 0 )
78 , bShutdownStarted( FALSE
)
79 , bDestroying( FALSE
)
81 SetPutDataReceivedHdl(LINK( this, CommunicationLinkViaSocket
, PutDataReceivedHdl
));
82 if ( !pMPostUserEvent
)
83 pMPostUserEvent
= new NAMESPACE_VOS(OMutex
);
84 // this is necassary to prevent the running thread from sending the close event
85 // before the open event has been sent.
91 CommunicationLinkViaSocket::~CommunicationLinkViaSocket()
95 while ( nConnectionClosedEventId
|| nDataReceivedEventId
)
98 NAMESPACE_VOS(OGuard
) aGuard( aMConnectionClosed
);
99 if ( nConnectionClosedEventId
)
101 GetpApp()->RemoveUserEvent( nConnectionClosedEventId
);
102 nConnectionClosedEventId
= 0;
103 INFO_MSG( CByteString("Event gelöscht"),
104 CByteString( "ConnectionClosedEvent aus Queue gelöscht"),
109 NAMESPACE_VOS(OGuard
) aGuard( aMDataReceived
);
110 if ( nDataReceivedEventId
)
112 GetpApp()->RemoveUserEvent( nDataReceivedEventId
);
113 nDataReceivedEventId
= 0;
114 delete GetServiceData();
115 INFO_MSG( CByteString("Event gelöscht"),
116 CByteString( "DataReceivedEvent aus Queue gelöscht"),
122 BOOL
CommunicationLinkViaSocket::ShutdownCommunication()
128 if ( GetStreamSocket() )
129 GetStreamSocket()->shutdown();
131 if ( GetStreamSocket() ) // Mal wieder nach oben verschoben, da sonst nicht vom Read runtergesprungen wird.
132 GetStreamSocket()->close();
134 resume(); // So daß das run auch die Schleife verlassen kann
138 NAMESPACE_VOS(OStreamSocket
) *pTempSocket
= GetStreamSocket();
139 SetStreamSocket( NULL
);
142 // ConnectionClosed(); Wird am Ende des Thread gerufen
153 BOOL
CommunicationLinkViaSocket::StopCommunication()
155 if ( !bShutdownStarted
)
157 return SimpleCommunicationLinkViaSocket::StopCommunication();
167 IMPL_LINK( CommunicationLinkViaSocket
, ShutdownLink
, void*, EMPTYARG
)
169 if ( !IsCommunicationError() )
170 ShutdownCommunication();
175 void CommunicationLinkViaSocket::WaitForShutdown()
177 if ( !bShutdownStarted
)
179 aShutdownTimer
.SetTimeout( 30000 ); // Should be 30 Seconds
180 aShutdownTimer
.SetTimeoutHdl( LINK( this, CommunicationLinkViaSocket
, ShutdownLink
) );
181 aShutdownTimer
.Start();
182 bShutdownStarted
= TRUE
;
186 while ( pMyManager
&& aShutdownTimer
.IsActive() )
188 if ( IsCommunicationError() )
192 ShutdownCommunication();
196 BOOL
CommunicationLinkViaSocket::IsCommunicationError()
198 return !isRunning() || SimpleCommunicationLinkViaSocket::IsCommunicationError();
201 void CommunicationLinkViaSocket::run()
203 BOOL bWasError
= FALSE
;
204 while ( schedule() && !bWasError
&& GetStreamSocket() )
206 if ( bWasError
|= !DoReceiveDataStream() )
209 TimeValue sNochEins
= {0, 1000000};
210 while ( schedule() && bIsInsideCallback
) // solange der letzte Callback nicht beendet ist
212 SetNewPacketAsCurrent();
215 NAMESPACE_VOS(OGuard
) aGuard( aMDataReceived
);
216 NAMESPACE_VOS(OGuard
) aGuard2( *pMPostUserEvent
);
217 mlPutDataReceived
.Call(this);
220 TimeValue sNochEins
= {0, 1000000};
221 while ( schedule() && bIsInsideCallback
) // solange der letzte Callback nicht beendet ist
226 NAMESPACE_VOS(OGuard
) aGuard( aMConnectionClosed
);
227 NAMESPACE_VOS(OGuard
) aGuard2( *pMPostUserEvent
);
228 nConnectionClosedEventId
= GetpApp()->PostUserEvent( LINK( this, CommunicationLinkViaSocket
, ConnectionClosed
) );
232 BOOL
CommunicationLinkViaSocket::DoTransferDataStream( SvStream
*pDataStream
, CMProtocol nProtocol
)
237 return SimpleCommunicationLinkViaSocket::DoTransferDataStream( pDataStream
, nProtocol
);
240 /// Dies ist ein virtueller Link!!!
241 long CommunicationLinkViaSocket::ConnectionClosed( void* EMPTYARG
)
244 NAMESPACE_VOS(OGuard
) aGuard( aMConnectionClosed
);
245 nConnectionClosedEventId
= 0; // Achtung!! alles andere muß oben gemacht werden.
247 ShutdownCommunication();
248 return CommunicationLink::ConnectionClosed( );
251 /// Dies ist ein virtueller Link!!!
252 long CommunicationLinkViaSocket::DataReceived( void* EMPTYARG
)
255 NAMESPACE_VOS(OGuard
) aGuard( aMDataReceived
);
256 nDataReceivedEventId
= 0; // Achtung!! alles andere muß oben gemacht werden.
258 return CommunicationLink::DataReceived( );
261 IMPL_LINK( CommunicationLinkViaSocket
, PutDataReceivedHdl
, CommunicationLinkViaSocket
*, EMPTYARG
)
263 nDataReceivedEventId
= GetpApp()->PostUserEvent( LINK( this, CommunicationLink
, DataReceived
) );
269 MultiCommunicationManager::MultiCommunicationManager( BOOL bUseMultiChannel
)
270 : CommunicationManager( bUseMultiChannel
)
271 , bGracefullShutdown( TRUE
)
273 ActiveLinks
= new CommunicationLinkList
;
274 InactiveLinks
= new CommunicationLinkList
;
277 MultiCommunicationManager::~MultiCommunicationManager()
281 if ( bGracefullShutdown
) // first try to collect all callbacks for closing channels
284 aTimeout
.SetTimeout( 40000 );
286 USHORT nLinkCount
= 0;
287 USHORT nNewLinkCount
= 0;
288 while ( aTimeout
.IsActive() )
291 nNewLinkCount
= GetCommunicationLinkCount();
292 if ( nNewLinkCount
== 0 )
294 if ( nNewLinkCount
!= nLinkCount
)
297 nLinkCount
= nNewLinkCount
;
302 // Alles weghauen, was nicht rechtzeitig auf die Bäume gekommen ist
303 // Was bei StopCommunication übrig geblieben ist, da es sich asynchron austragen wollte
304 USHORT i
= ActiveLinks
->Count();
307 CommunicationLinkRef rTempLink
= ActiveLinks
->GetObject( i
);
308 ActiveLinks
->Remove( i
);
309 rTempLink
->InvalidateManager();
310 rTempLink
->ReleaseReference();
314 /// Die Links zwischen ConnectionClosed und Destruktor.
315 /// Hier NICHT gerefcounted, da sie sich sonst im Kreis festhaten würden,
316 /// da die Links sich erst in ihrem Destruktor austragen
317 i
= InactiveLinks
->Count();
320 CommunicationLinkRef rTempLink
= InactiveLinks
->GetObject( i
);
321 InactiveLinks
->Remove( i
);
322 rTempLink
->InvalidateManager();
324 delete InactiveLinks
;
327 BOOL
MultiCommunicationManager::StopCommunication()
329 // Alle Verbindungen abbrechen
330 // ConnectionClosed entfernt die Links aus der Liste. Je nach Implementation syncron
331 // oder asyncron. Daher Von oben nach unten Abräumen, so daß sich nichts verschiebt.
332 USHORT i
= ActiveLinks
->Count();
336 if ( !ActiveLinks
->GetObject(i
-1)->StopCommunication() )
337 nFail
++; // Hochzählen, da Verbindung sich nicht (sofort) beenden lässt.
344 BOOL
MultiCommunicationManager::IsLinkValid( CommunicationLink
* pCL
)
346 if ( ActiveLinks
->Seek_Entry( pCL
) )
352 USHORT
MultiCommunicationManager::GetCommunicationLinkCount()
354 return ActiveLinks
->Count();
357 CommunicationLinkRef
MultiCommunicationManager::GetCommunicationLink( USHORT nNr
)
359 return ActiveLinks
->GetObject( nNr
);
362 void MultiCommunicationManager::CallConnectionOpened( CommunicationLink
* pCL
)
364 CommunicationLinkRef
rHold(pCL
); // Hält den Zeiger bis zum Ende des calls
365 ActiveLinks
->C40_PTR_INSERT(CommunicationLink
, pCL
);
368 CommunicationManager::CallConnectionOpened( pCL
);
371 void MultiCommunicationManager::CallConnectionClosed( CommunicationLink
* pCL
)
373 CommunicationLinkRef
rHold(pCL
); // Hält denm Zeiger bis zum Ende des calls
375 CommunicationManager::CallConnectionClosed( pCL
);
378 if ( ActiveLinks
->Seek_Entry( pCL
, &nPos
) )
380 InactiveLinks
->C40_PTR_INSERT(CommunicationLink
, pCL
); // Ohne Reference
381 ActiveLinks
->Remove( nPos
);
383 pCL
->ReleaseReference();
385 bIsCommunicationRunning
= ActiveLinks
->Count() > 0;
387 #if OSL_DEBUG_LEVEL > 1
392 void MultiCommunicationManager::DestroyingLink( CommunicationLink
*pCL
)
395 if ( InactiveLinks
->Seek_Entry( pCL
, &nPos
) )
396 InactiveLinks
->Remove( nPos
);
397 pCL
->InvalidateManager();
402 CommunicationManagerClient::CommunicationManagerClient( BOOL bUseMultiChannel
)
403 : MultiCommunicationManager( bUseMultiChannel
)
405 ByteString
aApplication("Something inside ");
406 aApplication
.Append( ByteString( DirEntry( Application::GetAppFileName() ).GetName(), gsl_getSystemTextEncoding() ) );
407 SetApplication( aApplication
);
412 CommunicationManagerServerViaSocket::CommunicationManagerServerViaSocket( ULONG nPort
, USHORT nMaxCon
, BOOL bUseMultiChannel
)
413 : CommunicationManagerServer( bUseMultiChannel
)
414 , nPortToListen( nPort
)
415 , nMaxConnections( nMaxCon
)
416 , pAcceptThread( NULL
)
420 CommunicationManagerServerViaSocket::~CommunicationManagerServerViaSocket()
425 BOOL
CommunicationManagerServerViaSocket::StartCommunication()
427 if ( !pAcceptThread
)
428 pAcceptThread
= new CommunicationManagerServerAcceptThread( this, nPortToListen
, nMaxConnections
);
433 BOOL
CommunicationManagerServerViaSocket::StopCommunication()
435 // Erst den Acceptor anhalten
436 delete pAcceptThread
;
437 pAcceptThread
= NULL
;
439 // Dann alle Verbindungen kappen
440 return CommunicationManagerServer::StopCommunication();
444 void CommunicationManagerServerViaSocket::AddConnection( CommunicationLink
*pNewConnection
)
446 CallConnectionOpened( pNewConnection
);
450 CommunicationManagerServerAcceptThread::CommunicationManagerServerAcceptThread( CommunicationManagerServerViaSocket
* pServer
, ULONG nPort
, USHORT nMaxCon
)
451 : pMyServer( pServer
)
452 , pAcceptorSocket( NULL
)
453 , nPortToListen( nPort
)
454 , nMaxConnections( nMaxCon
)
455 , nAddConnectionEventId( 0 )
456 , xmNewConnection( NULL
)
458 if ( !pMPostUserEvent
)
459 pMPostUserEvent
= new NAMESPACE_VOS(OMutex
);
464 CommunicationManagerServerAcceptThread::~CommunicationManagerServerAcceptThread()
466 #ifndef aUNX // Weil das Accept nicht abgebrochen werden kann, so terminiert wenigstens das Prog
467 // #62855# pl: gilt auch bei anderen Unixen
468 // die richtige Loesung waere natuerlich, etwas auf die pipe zu schreiben,
469 // was der thread als Abbruchbedingung erkennt
470 // oder wenigstens ein kill anstatt join
472 if ( pAcceptorSocket
)
473 pAcceptorSocket
->close(); // Dann das Accept unterbrechen
475 join(); // Warten bis fertig
477 if ( pAcceptorSocket
)
479 delete pAcceptorSocket
;
480 pAcceptorSocket
= NULL
;
483 DEBUGPRINTF ("Destructor CommunicationManagerServerAcceptThread Übersprungen!!!! (wegen Solaris BUG)\n");
486 NAMESPACE_VOS(OGuard
) aGuard( aMAddConnection
);
487 if ( nAddConnectionEventId
)
489 GetpApp()->RemoveUserEvent( nAddConnectionEventId
);
490 nAddConnectionEventId
= 0;
491 CommunicationLinkRef xNewConnection
= GetNewConnection();
492 INFO_MSG( CByteString("Event gelöscht"),
493 CByteString( "AddConnectionEvent aus Queue gelöscht"),
494 CM_MISC
, xNewConnection
);
495 xNewConnection
->InvalidateManager();
496 xNewConnection
.Clear(); // sollte das Objekt hier löschen
501 void CommunicationManagerServerAcceptThread::run()
503 if ( !nPortToListen
)
506 pAcceptorSocket
= new NAMESPACE_VOS(OAcceptorSocket
)();
507 NAMESPACE_VOS(OInetSocketAddr
) Addr
;
508 Addr
.setPort( nPortToListen
);
509 pAcceptorSocket
->setReuseAddr( 1 );
510 if ( !pAcceptorSocket
->bind( Addr
) )
514 if ( !pAcceptorSocket
->listen( nMaxConnections
) )
520 NAMESPACE_VOS(OStreamSocket
) *pStreamSocket
= NULL
;
524 pStreamSocket
= new NAMESPACE_VOS(OStreamSocket
);
525 switch ( pAcceptorSocket
->acceptConnection( *pStreamSocket
) )
527 case NAMESPACE_VOS(ISocketTypes::TResult_Ok
):
529 pStreamSocket
->setTcpNoDelay( 1 );
531 TimeValue sNochEins
= {0, 100};
532 while ( schedule() && xmNewConnection
.Is() ) // Solange die letzte Connection nicht abgeholt wurde warten wir
534 xmNewConnection
= new CommunicationLinkViaSocket( pMyServer
, pStreamSocket
);
535 xmNewConnection
->StartCallback();
537 NAMESPACE_VOS(OGuard
) aGuard( aMAddConnection
);
538 NAMESPACE_VOS(OGuard
) aGuard2( *pMPostUserEvent
);
539 nAddConnectionEventId
= GetpApp()->PostUserEvent( LINK( this, CommunicationManagerServerAcceptThread
, AddConnection
) );
543 case NAMESPACE_VOS(ISocketTypes::TResult_TimedOut
):
544 delete pStreamSocket
;
545 pStreamSocket
= NULL
;
547 case NAMESPACE_VOS(ISocketTypes::TResult_Error
):
548 delete pStreamSocket
;
549 pStreamSocket
= NULL
;
552 case NAMESPACE_VOS(ISocketTypes::TResult_Interrupted
):
553 case NAMESPACE_VOS(ISocketTypes::TResult_InProgress
):
554 break; // -Wall not handled...
560 IMPL_LINK( CommunicationManagerServerAcceptThread
, AddConnection
, void*, EMPTYARG
)
563 NAMESPACE_VOS(OGuard
) aGuard( aMAddConnection
);
564 nAddConnectionEventId
= 0;
566 pMyServer
->AddConnection( xmNewConnection
);
567 xmNewConnection
.Clear();
572 #define GETSET(aVar, KeyName, Dafault) \
573 aVar = aConf.ReadKey(KeyName,"No Entry"); \
574 if ( aVar == "No Entry" ) \
577 aConf.WriteKey(KeyName, aVar); \
581 CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( ByteString aHost
, ULONG nPort
, BOOL bUseMultiChannel
)
582 : CommunicationManagerClient( bUseMultiChannel
)
583 , aHostToTalk( aHost
)
584 , nPortToTalk( nPort
)
588 CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( BOOL bUseMultiChannel
)
589 : CommunicationManagerClient( bUseMultiChannel
)
595 CommunicationManagerClientViaSocket::~CommunicationManagerClientViaSocket()