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