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