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 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 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 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 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 160 IMPL_LINK( CommunicationLinkViaSocket, ShutdownLink, void*, EMPTYARG ) 161 { 162 if ( !IsCommunicationError() ) 163 ShutdownCommunication(); 164 return 0; 165 } 166 167 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 189 sal_Bool CommunicationLinkViaSocket::IsCommunicationError() 190 { 191 return !isRunning() || SimpleCommunicationLinkViaSocket::IsCommunicationError(); 192 } 193 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 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!!! 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!!! 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 255 IMPL_LINK( CommunicationLinkViaSocket, PutDataReceivedHdl, CommunicationLinkViaSocket*, EMPTYARG ) 256 { 257 nDataReceivedEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationLink, DataReceived ) ); 258 return 0; 259 } 260 261 262 263 MultiCommunicationManager::MultiCommunicationManager( sal_Bool bUseMultiChannel ) 264 : CommunicationManager( bUseMultiChannel ) 265 , bGracefullShutdown( sal_True ) 266 { 267 ActiveLinks = new CommunicationLinkList; 268 InactiveLinks = new CommunicationLinkList; 269 } 270 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 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 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 346 sal_uInt16 MultiCommunicationManager::GetCommunicationLinkCount() 347 { 348 return ActiveLinks->Count(); 349 } 350 351 CommunicationLinkRef MultiCommunicationManager::GetCommunicationLink( sal_uInt16 nNr ) 352 { 353 return ActiveLinks->GetObject( nNr ); 354 } 355 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 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 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 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 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 414 CommunicationManagerServerViaSocket::~CommunicationManagerServerViaSocket() 415 { 416 StopCommunication(); 417 } 418 419 sal_Bool CommunicationManagerServerViaSocket::StartCommunication() 420 { 421 if ( !pAcceptThread ) 422 pAcceptThread = new CommunicationManagerServerAcceptThread( this, nPortToListen, nMaxConnections ); 423 return sal_True; 424 } 425 426 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 438 void CommunicationManagerServerViaSocket::AddConnection( CommunicationLink *pNewConnection ) 439 { 440 CallConnectionOpened( pNewConnection ); 441 } 442 443 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 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 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 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 575 CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( ByteString aHost, sal_uLong nPort, sal_Bool bUseMultiChannel ) 576 : CommunicationManagerClient( bUseMultiChannel ) 577 , aHostToTalk( aHost ) 578 , nPortToTalk( nPort ) 579 { 580 } 581 582 CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( sal_Bool bUseMultiChannel ) 583 : CommunicationManagerClient( bUseMultiChannel ) 584 , aHostToTalk( "" ) 585 , nPortToTalk( 0 ) 586 { 587 } 588 589 CommunicationManagerClientViaSocket::~CommunicationManagerClientViaSocket() 590 { 591 } 592 593 594