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