xref: /AOO41X/main/automation/source/communi/communi.cxx (revision ca62e2c2083b5d0995f1245bad6c2edfb455fbec)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_automation.hxx"
26 #include <stdio.h>
27 #if OSL_DEBUG_LEVEL > 1
28 #define DEBUGPRINTF(x) { printf(x); fflush( stdout ); }
29 #else
30 #define DEBUGPRINTF(x)
31 #endif
32 #include <tools/debug.hxx>
33 #include <vcl/svapp.hxx>
34 #include <vos/socket.hxx>
35 #include <tools/stream.hxx>
36 #include <vcl/timer.hxx>
37 #include <tools/fsys.hxx>
38 
39 #include <automation/communi.hxx>
40 
41 
42 /*  Um den Destruktor protected zu machen wurde unten das delete entfernt.
43     Die Methode wird ohnehin hucht benutzt.
44 //              delete *((AE*)pData+n);
45 */
46 
47 #undef  SV_IMPL_PTRARR_SORT
48 #define SV_IMPL_PTRARR_SORT( nm,AE )\
49 _SV_IMPL_SORTAR_ALG( nm,AE )\
50     void nm::DeleteAndDestroy( sal_uInt16 nP, sal_uInt16 nL ) { \
51         if( nL ) {\
52             DBG_ASSERT( nP < nA && nP + nL <= nA, "ERR_VAR_DEL" );\
53             for( sal_uInt16 n=nP; n < nP + nL; n++ ) \
54                 DBG_ERROR("Das Element der Liste wurde nicht gel�scht"); \
55             SvPtrarr::Remove( nP, nL ); \
56         } \
57     } \
58 _SV_SEEK_PTR( nm, AE )
59 
60 
61 
62 
63 SV_IMPL_PTRARR_SORT( CommunicationLinkList, CommunicationLink* );
64 
65 vos::OMutex *pMPostUserEvent=NULL;      // Notwendig, da nicht threadfest
66 
CommunicationLinkViaSocket(CommunicationManager * pMan,vos::OStreamSocket * pSocket)67 CommunicationLinkViaSocket::CommunicationLinkViaSocket( CommunicationManager *pMan, vos::OStreamSocket *pSocket )
68 : SimpleCommunicationLinkViaSocket( pMan, pSocket )
69 , nConnectionClosedEventId( 0 )
70 , nDataReceivedEventId( 0 )
71 , bShutdownStarted( sal_False )
72 , bDestroying( sal_False )
73 {
74     SetPutDataReceivedHdl(LINK( this, CommunicationLinkViaSocket, PutDataReceivedHdl ));
75     if ( !pMPostUserEvent )
76         pMPostUserEvent = new vos::OMutex;
77     // this is necassary to prevent the running thread from sending the close event
78     // before the open event has been sent.
79     StartCallback();
80 
81     create();
82 }
83 
~CommunicationLinkViaSocket()84 CommunicationLinkViaSocket::~CommunicationLinkViaSocket()
85 {
86     bDestroying = sal_True;
87     StopCommunication();
88     while ( nConnectionClosedEventId || nDataReceivedEventId )
89         GetpApp()->Yield();
90     {
91         vos::OGuard aGuard( aMConnectionClosed );
92         if ( nConnectionClosedEventId )
93         {
94             GetpApp()->RemoveUserEvent( nConnectionClosedEventId );
95             nConnectionClosedEventId = 0;
96             INFO_MSG( CByteString("Event gel�scht"),
97                 CByteString( "ConnectionClosedEvent aus Queue gel�scht"),
98                 CM_MISC, NULL );
99         }
100     }
101     {
102         vos::OGuard aGuard( aMDataReceived );
103         if ( nDataReceivedEventId )
104         {
105             GetpApp()->RemoveUserEvent( nDataReceivedEventId );
106             nDataReceivedEventId = 0;
107             delete GetServiceData();
108             INFO_MSG( CByteString("Event gel�scht"),
109                 CByteString( "DataReceivedEvent aus Queue gel�scht"),
110                 CM_MISC, NULL );
111         }
112     }
113 }
114 
ShutdownCommunication()115 sal_Bool CommunicationLinkViaSocket::ShutdownCommunication()
116 {
117     if ( isRunning() )
118     {
119 
120         terminate();
121         if ( GetStreamSocket() )
122             GetStreamSocket()->shutdown();
123 
124         if ( GetStreamSocket() )    // Mal wieder nach oben verschoben, da sonst nicht vom Read runtergesprungen wird.
125             GetStreamSocket()->close();
126 
127         resume();   // So da� das run auch die Schleife verlassen kann
128 
129         join();
130 
131         vos::OStreamSocket *pTempSocket = GetStreamSocket();
132         SetStreamSocket( NULL );
133         delete pTempSocket;
134 
135 //      ConnectionClosed();     Wird am Ende des Thread gerufen
136 
137     }
138     else
139     {
140         join();
141     }
142 
143     return sal_True;
144 }
145 
StopCommunication()146 sal_Bool CommunicationLinkViaSocket::StopCommunication()
147 {
148     if ( !bShutdownStarted )
149     {
150         return SimpleCommunicationLinkViaSocket::StopCommunication();
151     }
152     else
153     {
154         WaitForShutdown();
155         return sal_True;
156     }
157 }
158 
159 
IMPL_LINK(CommunicationLinkViaSocket,ShutdownLink,void *,EMPTYARG)160 IMPL_LINK( CommunicationLinkViaSocket, ShutdownLink, void*, EMPTYARG )
161 {
162     if ( !IsCommunicationError() )
163         ShutdownCommunication();
164     return 0;
165 }
166 
167 
WaitForShutdown()168 void CommunicationLinkViaSocket::WaitForShutdown()
169 {
170     if ( !bShutdownStarted )
171     {
172         aShutdownTimer.SetTimeout( 30000 );     // Should be 30 Seconds
173         aShutdownTimer.SetTimeoutHdl( LINK( this, CommunicationLinkViaSocket, ShutdownLink ) );
174         aShutdownTimer.Start();
175         bShutdownStarted = sal_True;
176     }
177     if ( bDestroying )
178     {
179         while ( pMyManager && aShutdownTimer.IsActive() )
180         {
181             if ( IsCommunicationError() )
182                 return;
183             GetpApp()->Yield();
184         }
185         ShutdownCommunication();
186     }
187 }
188 
IsCommunicationError()189 sal_Bool CommunicationLinkViaSocket::IsCommunicationError()
190 {
191     return !isRunning() || SimpleCommunicationLinkViaSocket::IsCommunicationError();
192 }
193 
run()194 void CommunicationLinkViaSocket::run()
195 {
196     sal_Bool bWasError = sal_False;
197     while ( schedule() && !bWasError && GetStreamSocket() )
198     {
199         bWasError |= !DoReceiveDataStream();
200         if( bWasError)
201             continue;
202 
203         TimeValue sNochEins = {0, 1000000};
204         while ( schedule() && bIsInsideCallback )   // solange der letzte Callback nicht beendet ist
205             sleep( sNochEins );
206         SetNewPacketAsCurrent();
207         StartCallback();
208         {
209             vos::OGuard aGuard( aMDataReceived );
210             vos::OGuard aGuard2( *pMPostUserEvent );
211             mlPutDataReceived.Call(this);
212         }
213     }
214     TimeValue sNochEins = {0, 1000000};
215     while ( schedule() && bIsInsideCallback )   // solange der letzte Callback nicht beendet ist
216         sleep( sNochEins );
217 
218     StartCallback();
219     {
220         vos::OGuard aGuard( aMConnectionClosed );
221         vos::OGuard aGuard2( *pMPostUserEvent );
222         nConnectionClosedEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationLinkViaSocket, ConnectionClosed ) );
223     }
224 }
225 
DoTransferDataStream(SvStream * pDataStream,CMProtocol nProtocol)226 sal_Bool CommunicationLinkViaSocket::DoTransferDataStream( SvStream *pDataStream, CMProtocol nProtocol )
227 {
228     if ( !isRunning() )
229         return sal_False;
230 
231     return SimpleCommunicationLinkViaSocket::DoTransferDataStream( pDataStream, nProtocol );
232 }
233 
234 /// Dies ist ein virtueller Link!!!
ConnectionClosed(void * EMPTYARG)235 long CommunicationLinkViaSocket::ConnectionClosed( void* EMPTYARG )
236 {
237     {
238         vos::OGuard aGuard( aMConnectionClosed );
239         nConnectionClosedEventId = 0;   // Achtung!! alles andere mu� oben gemacht werden.
240     }
241     ShutdownCommunication();
242     return CommunicationLink::ConnectionClosed( );
243 }
244 
245 /// Dies ist ein virtueller Link!!!
DataReceived(void * EMPTYARG)246 long CommunicationLinkViaSocket::DataReceived( void* EMPTYARG )
247 {
248     {
249         vos::OGuard aGuard( aMDataReceived );
250         nDataReceivedEventId = 0;   // Achtung!! alles andere mu� oben gemacht werden.
251     }
252     return CommunicationLink::DataReceived( );
253 }
254 
IMPL_LINK(CommunicationLinkViaSocket,PutDataReceivedHdl,CommunicationLinkViaSocket *,EMPTYARG)255 IMPL_LINK( CommunicationLinkViaSocket, PutDataReceivedHdl, CommunicationLinkViaSocket*, EMPTYARG )
256 {
257     nDataReceivedEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationLink, DataReceived ) );
258     return 0;
259 }
260 
261 
262 
MultiCommunicationManager(sal_Bool bUseMultiChannel)263 MultiCommunicationManager::MultiCommunicationManager( sal_Bool bUseMultiChannel )
264 : CommunicationManager( bUseMultiChannel )
265 , bGracefullShutdown( sal_True )
266 {
267     ActiveLinks = new CommunicationLinkList;
268     InactiveLinks = new CommunicationLinkList;
269 }
270 
~MultiCommunicationManager()271 MultiCommunicationManager::~MultiCommunicationManager()
272 {
273     StopCommunication();
274 
275     if ( bGracefullShutdown )   // first try to collect all callbacks for closing channels
276     {
277         Timer aTimeout;
278         aTimeout.SetTimeout( 40000 );
279         aTimeout.Start();
280         sal_uInt16 nLinkCount = 0;
281         sal_uInt16 nNewLinkCount = 0;
282         while ( aTimeout.IsActive() )
283         {
284             GetpApp()->Yield();
285             nNewLinkCount = GetCommunicationLinkCount();
286             if ( nNewLinkCount == 0 )
287                 aTimeout.Stop();
288             if ( nNewLinkCount != nLinkCount )
289             {
290                 aTimeout.Start();
291                 nLinkCount = nNewLinkCount;
292             }
293         }
294     }
295 
296     // Alles weghauen, was nicht rechtzeitig auf die B�ume gekommen ist
297     // Was bei StopCommunication �brig geblieben ist, da es sich asynchron austragen wollte
298     sal_uInt16 i = ActiveLinks->Count();
299     while ( i-- )
300     {
301         CommunicationLinkRef rTempLink = ActiveLinks->GetObject( i );
302         ActiveLinks->Remove( i );
303         rTempLink->InvalidateManager();
304         rTempLink->ReleaseReference();
305     }
306     delete ActiveLinks;
307 
308     /// Die Links zwischen ConnectionClosed und Destruktor.
309     /// Hier NICHT gerefcounted, da sie sich sonst im Kreis festhaten w�rden,
310     /// da die Links sich erst in ihrem Destruktor austragen
311     i = InactiveLinks->Count();
312     while ( i-- )
313     {
314         CommunicationLinkRef rTempLink = InactiveLinks->GetObject( i );
315         InactiveLinks->Remove( i );
316         rTempLink->InvalidateManager();
317     }
318     delete InactiveLinks;
319 }
320 
StopCommunication()321 sal_Bool MultiCommunicationManager::StopCommunication()
322 {
323     // Alle Verbindungen abbrechen
324     // ConnectionClosed entfernt die Links aus der Liste. Je nach Implementation syncron
325     // oder asyncron. Daher Von oben nach unten Abr�umen, so da� sich nichts verschiebt.
326     sal_uInt16 i = ActiveLinks->Count();
327     int nFail = 0;
328     while ( i )
329     {
330         if ( !ActiveLinks->GetObject(i-1)->StopCommunication() )
331             nFail++;    // Hochz�hlen, da Verbindung sich nicht (sofort) beenden l�sst.
332         i--;
333     }
334 
335     return nFail == 0;
336 }
337 
IsLinkValid(CommunicationLink * pCL)338 sal_Bool MultiCommunicationManager::IsLinkValid( CommunicationLink* pCL )
339 {
340     if ( ActiveLinks->Seek_Entry( pCL ) )
341         return sal_True;
342     else
343         return sal_False;
344 }
345 
GetCommunicationLinkCount()346 sal_uInt16 MultiCommunicationManager::GetCommunicationLinkCount()
347 {
348     return ActiveLinks->Count();
349 }
350 
GetCommunicationLink(sal_uInt16 nNr)351 CommunicationLinkRef MultiCommunicationManager::GetCommunicationLink( sal_uInt16 nNr )
352 {
353     return ActiveLinks->GetObject( nNr );
354 }
355 
CallConnectionOpened(CommunicationLink * pCL)356 void MultiCommunicationManager::CallConnectionOpened( CommunicationLink* pCL )
357 {
358     CommunicationLinkRef rHold(pCL);    // H�lt den Zeiger bis zum Ende des calls
359     ActiveLinks->C40_PTR_INSERT(CommunicationLink, pCL);
360     rHold->AddRef();
361 
362     CommunicationManager::CallConnectionOpened( pCL );
363 }
364 
CallConnectionClosed(CommunicationLink * pCL)365 void MultiCommunicationManager::CallConnectionClosed( CommunicationLink* pCL )
366 {
367     CommunicationLinkRef rHold(pCL);    // H�lt denm Zeiger bis zum Ende des calls
368 
369     CommunicationManager::CallConnectionClosed( pCL );
370 
371     sal_uInt16 nPos;
372     if ( ActiveLinks->Seek_Entry( pCL, &nPos ) )
373     {
374         InactiveLinks->C40_PTR_INSERT(CommunicationLink, pCL);  // Ohne Reference
375         ActiveLinks->Remove( nPos );
376     }
377     pCL->ReleaseReference();
378 
379     bIsCommunicationRunning = ActiveLinks->Count() > 0;
380 //  delete pCL;
381 #if OSL_DEBUG_LEVEL > 1
382         rHold->bFlag = sal_True;
383 #endif
384 }
385 
DestroyingLink(CommunicationLink * pCL)386 void MultiCommunicationManager::DestroyingLink( CommunicationLink *pCL )
387 {
388     sal_uInt16 nPos;
389     if ( InactiveLinks->Seek_Entry( pCL, &nPos ) )
390         InactiveLinks->Remove( nPos );
391     pCL->InvalidateManager();
392 }
393 
394 
395 
CommunicationManagerClient(sal_Bool bUseMultiChannel)396 CommunicationManagerClient::CommunicationManagerClient( sal_Bool bUseMultiChannel )
397 : MultiCommunicationManager( bUseMultiChannel )
398 {
399     ByteString aApplication("Something inside ");
400     aApplication.Append( ByteString( DirEntry( Application::GetAppFileName() ).GetName(), gsl_getSystemTextEncoding() ) );
401     SetApplication( aApplication );
402 }
403 
404 
405 
CommunicationManagerServerViaSocket(sal_uLong nPort,sal_uInt16 nMaxCon,sal_Bool bUseMultiChannel)406 CommunicationManagerServerViaSocket::CommunicationManagerServerViaSocket( sal_uLong nPort, sal_uInt16 nMaxCon, sal_Bool bUseMultiChannel )
407 : CommunicationManagerServer( bUseMultiChannel )
408 , nPortToListen( nPort )
409 , nMaxConnections( nMaxCon )
410 , pAcceptThread( NULL )
411 {
412 }
413 
~CommunicationManagerServerViaSocket()414 CommunicationManagerServerViaSocket::~CommunicationManagerServerViaSocket()
415 {
416     StopCommunication();
417 }
418 
StartCommunication()419 sal_Bool CommunicationManagerServerViaSocket::StartCommunication()
420 {
421     if ( !pAcceptThread )
422         pAcceptThread = new CommunicationManagerServerAcceptThread( this, nPortToListen, nMaxConnections );
423     return sal_True;
424 }
425 
426 
StopCommunication()427 sal_Bool CommunicationManagerServerViaSocket::StopCommunication()
428 {
429     // Erst den Acceptor anhalten
430     delete pAcceptThread;
431     pAcceptThread = NULL;
432 
433     // Dann alle Verbindungen kappen
434     return CommunicationManagerServer::StopCommunication();
435 }
436 
437 
AddConnection(CommunicationLink * pNewConnection)438 void CommunicationManagerServerViaSocket::AddConnection( CommunicationLink *pNewConnection )
439 {
440     CallConnectionOpened( pNewConnection );
441 }
442 
443 
CommunicationManagerServerAcceptThread(CommunicationManagerServerViaSocket * pServer,sal_uLong nPort,sal_uInt16 nMaxCon)444 CommunicationManagerServerAcceptThread::CommunicationManagerServerAcceptThread( CommunicationManagerServerViaSocket* pServer, sal_uLong nPort, sal_uInt16 nMaxCon )
445 : pMyServer( pServer )
446 , pAcceptorSocket( NULL )
447 , nPortToListen( nPort )
448 , nMaxConnections( nMaxCon )
449 , nAddConnectionEventId( 0 )
450 , xmNewConnection( NULL )
451 {
452     if ( !pMPostUserEvent )
453         pMPostUserEvent = new vos::OMutex;
454     create();
455 }
456 
457 
~CommunicationManagerServerAcceptThread()458 CommunicationManagerServerAcceptThread::~CommunicationManagerServerAcceptThread()
459 {
460 #ifndef aUNX        // Weil das Accept nicht abgebrochen werden kann, so terminiert wenigstens das Prog
461     // #62855# pl: gilt auch bei anderen Unixen
462     // die richtige Loesung waere natuerlich, etwas auf die pipe zu schreiben,
463     // was der thread als Abbruchbedingung erkennt
464     // oder wenigstens ein kill anstatt join
465     terminate();
466     if ( pAcceptorSocket )
467         pAcceptorSocket->close();   // Dann das Accept unterbrechen
468 
469     join();     // Warten bis fertig
470 
471     if ( pAcceptorSocket )
472     {
473         delete pAcceptorSocket;
474         pAcceptorSocket = NULL;
475     }
476 #else
477     DEBUGPRINTF ("Destructor CommunicationManagerServerAcceptThread �bersprungen!!!! (wegen Solaris BUG)\n");
478 #endif
479     {
480         vos::OGuard aGuard( aMAddConnection );
481         if ( nAddConnectionEventId )
482         {
483             GetpApp()->RemoveUserEvent( nAddConnectionEventId );
484             nAddConnectionEventId = 0;
485             CommunicationLinkRef xNewConnection = GetNewConnection();
486             INFO_MSG( CByteString("Event gel�scht"),
487                 CByteString( "AddConnectionEvent aus Queue gel�scht"),
488                 CM_MISC, xNewConnection );
489             xNewConnection->InvalidateManager();
490             xNewConnection.Clear(); // sollte das Objekt hier l�schen
491         }
492     }
493 }
494 
run()495 void CommunicationManagerServerAcceptThread::run()
496 {
497     if ( !nPortToListen )
498         return;
499 
500     pAcceptorSocket = new vos::OAcceptorSocket();
501     vos::OInetSocketAddr Addr;
502     Addr.setPort( nPortToListen );
503     pAcceptorSocket->setReuseAddr( 1 );
504     if ( !pAcceptorSocket->bind( Addr ) )
505     {
506         return;
507     }
508     if ( !pAcceptorSocket->listen( nMaxConnections ) )
509     {
510         return;
511     }
512 
513 
514     vos::OStreamSocket *pStreamSocket = NULL;
515 
516     while ( schedule() )
517     {
518         pStreamSocket = new vos::OStreamSocket;
519         switch ( pAcceptorSocket->acceptConnection( *pStreamSocket ) )
520         {
521         case vos::ISocketTypes::TResult_Ok:
522             {
523                 pStreamSocket->setTcpNoDelay( 1 );
524 
525                 TimeValue sNochEins = {0, 100};
526                 while ( schedule() && xmNewConnection.Is() )    // Solange die letzte Connection nicht abgeholt wurde warten wir
527                     sleep( sNochEins );
528                 xmNewConnection = new CommunicationLinkViaSocket( pMyServer, pStreamSocket );
529                 xmNewConnection->StartCallback();
530                 {
531                     vos::OGuard aGuard( aMAddConnection );
532                     vos::OGuard aGuard2( *pMPostUserEvent );
533                     nAddConnectionEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationManagerServerAcceptThread, AddConnection ) );
534                 }
535             }
536             break;
537         case vos::ISocketTypes::TResult_TimedOut:
538             delete pStreamSocket;
539             pStreamSocket = NULL;
540             break;
541         case vos::ISocketTypes::TResult_Error:
542             delete pStreamSocket;
543             pStreamSocket = NULL;
544             break;
545 
546         case vos::ISocketTypes::TResult_Interrupted:
547         case vos::ISocketTypes::TResult_InProgress:
548             break;  // -Wall not handled...
549         }
550     }
551 }
552 
553 
IMPL_LINK(CommunicationManagerServerAcceptThread,AddConnection,void *,EMPTYARG)554 IMPL_LINK( CommunicationManagerServerAcceptThread, AddConnection, void*, EMPTYARG )
555 {
556     {
557         vos::OGuard aGuard( aMAddConnection );
558         nAddConnectionEventId = 0;
559     }
560     pMyServer->AddConnection( xmNewConnection );
561     xmNewConnection.Clear();
562     return 1;
563 }
564 
565 
566 #define GETSET(aVar, KeyName, Dafault)                 \
567     aVar = aConf.ReadKey(KeyName,"No Entry");          \
568     if ( aVar == "No Entry" )                          \
569     {                                                  \
570         aVar = Dafault;                                \
571         aConf.WriteKey(KeyName, aVar);                 \
572     }
573 
574 
CommunicationManagerClientViaSocket(ByteString aHost,sal_uLong nPort,sal_Bool bUseMultiChannel)575 CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( ByteString aHost, sal_uLong nPort, sal_Bool bUseMultiChannel )
576 : CommunicationManagerClient( bUseMultiChannel )
577 , aHostToTalk( aHost )
578 , nPortToTalk( nPort )
579 {
580 }
581 
CommunicationManagerClientViaSocket(sal_Bool bUseMultiChannel)582 CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( sal_Bool bUseMultiChannel )
583 : CommunicationManagerClient( bUseMultiChannel )
584 , aHostToTalk( "" )
585 , nPortToTalk( 0 )
586 {
587 }
588 
~CommunicationManagerClientViaSocket()589 CommunicationManagerClientViaSocket::~CommunicationManagerClientViaSocket()
590 {
591 }
592 
593 
594