update dev300-m58
[ooovba.git] / automation / source / communi / communi.cxx
blob6d6515414200e6127eceaf4af39f27ef630444cf
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: communi.cxx,v $
10 * $Revision: 1.9 $
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"
33 #include <stdio.h>
34 #if OSL_DEBUG_LEVEL > 1
35 #define DEBUGPRINTF(x) { printf(x); fflush( stdout ); }
36 #else
37 #define DEBUGPRINTF(x)
38 #endif
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 ) { \
58 if( 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 ); \
63 } \
64 } \
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.
86 StartCallback();
88 create();
91 CommunicationLinkViaSocket::~CommunicationLinkViaSocket()
93 bDestroying = TRUE;
94 StopCommunication();
95 while ( nConnectionClosedEventId || nDataReceivedEventId )
96 GetpApp()->Yield();
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"),
105 CM_MISC, NULL );
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"),
117 CM_MISC, NULL );
122 BOOL CommunicationLinkViaSocket::ShutdownCommunication()
124 if ( isRunning() )
127 terminate();
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
136 join();
138 NAMESPACE_VOS(OStreamSocket) *pTempSocket = GetStreamSocket();
139 SetStreamSocket( NULL );
140 delete pTempSocket;
142 // ConnectionClosed(); Wird am Ende des Thread gerufen
145 else
147 join();
150 return TRUE;
153 BOOL CommunicationLinkViaSocket::StopCommunication()
155 if ( !bShutdownStarted )
157 return SimpleCommunicationLinkViaSocket::StopCommunication();
159 else
161 WaitForShutdown();
162 return TRUE;
167 IMPL_LINK( CommunicationLinkViaSocket, ShutdownLink, void*, EMPTYARG )
169 if ( !IsCommunicationError() )
170 ShutdownCommunication();
171 return 0;
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;
184 if ( bDestroying )
186 while ( pMyManager && aShutdownTimer.IsActive() )
188 if ( IsCommunicationError() )
189 return;
190 GetpApp()->Yield();
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() )
207 continue;
209 TimeValue sNochEins = {0, 1000000};
210 while ( schedule() && bIsInsideCallback ) // solange der letzte Callback nicht beendet ist
211 sleep( sNochEins );
212 SetNewPacketAsCurrent();
213 StartCallback();
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
222 sleep( sNochEins );
224 StartCallback();
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 )
234 if ( !isRunning() )
235 return FALSE;
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 ) );
264 return 0;
269 MultiCommunicationManager::MultiCommunicationManager( BOOL bUseMultiChannel )
270 : CommunicationManager( bUseMultiChannel )
271 , bGracefullShutdown( TRUE )
273 ActiveLinks = new CommunicationLinkList;
274 InactiveLinks = new CommunicationLinkList;
277 MultiCommunicationManager::~MultiCommunicationManager()
279 StopCommunication();
281 if ( bGracefullShutdown ) // first try to collect all callbacks for closing channels
283 Timer aTimeout;
284 aTimeout.SetTimeout( 40000 );
285 aTimeout.Start();
286 USHORT nLinkCount = 0;
287 USHORT nNewLinkCount = 0;
288 while ( aTimeout.IsActive() )
290 GetpApp()->Yield();
291 nNewLinkCount = GetCommunicationLinkCount();
292 if ( nNewLinkCount == 0 )
293 aTimeout.Stop();
294 if ( nNewLinkCount != nLinkCount )
296 aTimeout.Start();
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();
305 while ( i-- )
307 CommunicationLinkRef rTempLink = ActiveLinks->GetObject( i );
308 ActiveLinks->Remove( i );
309 rTempLink->InvalidateManager();
310 rTempLink->ReleaseReference();
312 delete ActiveLinks;
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();
318 while ( i-- )
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();
333 int nFail = 0;
334 while ( i )
336 if ( !ActiveLinks->GetObject(i-1)->StopCommunication() )
337 nFail++; // Hochzählen, da Verbindung sich nicht (sofort) beenden lässt.
338 i--;
341 return nFail == 0;
344 BOOL MultiCommunicationManager::IsLinkValid( CommunicationLink* pCL )
346 if ( ActiveLinks->Seek_Entry( pCL ) )
347 return TRUE;
348 else
349 return FALSE;
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);
366 rHold->AddRef();
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 );
377 USHORT nPos;
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;
386 // delete pCL;
387 #if OSL_DEBUG_LEVEL > 1
388 rHold->bFlag = TRUE;
389 #endif
392 void MultiCommunicationManager::DestroyingLink( CommunicationLink *pCL )
394 USHORT nPos;
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()
422 StopCommunication();
425 BOOL CommunicationManagerServerViaSocket::StartCommunication()
427 if ( !pAcceptThread )
428 pAcceptThread = new CommunicationManagerServerAcceptThread( this, nPortToListen, nMaxConnections );
429 return TRUE;
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);
460 create();
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
471 terminate();
472 if ( pAcceptorSocket )
473 pAcceptorSocket->close(); // Dann das Accept unterbrechen
475 join(); // Warten bis fertig
477 if ( pAcceptorSocket )
479 delete pAcceptorSocket;
480 pAcceptorSocket = NULL;
482 #else
483 DEBUGPRINTF ("Destructor CommunicationManagerServerAcceptThread Übersprungen!!!! (wegen Solaris BUG)\n");
484 #endif
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 )
504 return;
506 pAcceptorSocket = new NAMESPACE_VOS(OAcceptorSocket)();
507 NAMESPACE_VOS(OInetSocketAddr) Addr;
508 Addr.setPort( nPortToListen );
509 pAcceptorSocket->setReuseAddr( 1 );
510 if ( !pAcceptorSocket->bind( Addr ) )
512 return;
514 if ( !pAcceptorSocket->listen( nMaxConnections ) )
516 return;
520 NAMESPACE_VOS(OStreamSocket) *pStreamSocket = NULL;
522 while ( schedule() )
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
533 sleep( sNochEins );
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 ) );
542 break;
543 case NAMESPACE_VOS(ISocketTypes::TResult_TimedOut):
544 delete pStreamSocket;
545 pStreamSocket = NULL;
546 break;
547 case NAMESPACE_VOS(ISocketTypes::TResult_Error):
548 delete pStreamSocket;
549 pStreamSocket = NULL;
550 break;
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();
568 return 1;
572 #define GETSET(aVar, KeyName, Dafault) \
573 aVar = aConf.ReadKey(KeyName,"No Entry"); \
574 if ( aVar == "No Entry" ) \
576 aVar = Dafault; \
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 )
590 , aHostToTalk( "" )
591 , nPortToTalk( 0 )
595 CommunicationManagerClientViaSocket::~CommunicationManagerClientViaSocket()