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