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 if ( bWasError |= !DoReceiveDataStream() ) 200 continue; 201 202 TimeValue sNochEins = {0, 1000000}; 203 while ( schedule() && bIsInsideCallback ) // solange der letzte Callback nicht beendet ist 204 sleep( sNochEins ); 205 SetNewPacketAsCurrent(); 206 StartCallback(); 207 { 208 vos::OGuard aGuard( aMDataReceived ); 209 vos::OGuard aGuard2( *pMPostUserEvent ); 210 mlPutDataReceived.Call(this); 211 } 212 } 213 TimeValue sNochEins = {0, 1000000}; 214 while ( schedule() && bIsInsideCallback ) // solange der letzte Callback nicht beendet ist 215 sleep( sNochEins ); 216 217 StartCallback(); 218 { 219 vos::OGuard aGuard( aMConnectionClosed ); 220 vos::OGuard aGuard2( *pMPostUserEvent ); 221 nConnectionClosedEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationLinkViaSocket, ConnectionClosed ) ); 222 } 223 } 224 225 sal_Bool CommunicationLinkViaSocket::DoTransferDataStream( SvStream *pDataStream, CMProtocol nProtocol ) 226 { 227 if ( !isRunning() ) 228 return sal_False; 229 230 return SimpleCommunicationLinkViaSocket::DoTransferDataStream( pDataStream, nProtocol ); 231 } 232 233 /// Dies ist ein virtueller Link!!! 234 long CommunicationLinkViaSocket::ConnectionClosed( void* EMPTYARG ) 235 { 236 { 237 vos::OGuard aGuard( aMConnectionClosed ); 238 nConnectionClosedEventId = 0; // Achtung!! alles andere mu� oben gemacht werden. 239 } 240 ShutdownCommunication(); 241 return CommunicationLink::ConnectionClosed( ); 242 } 243 244 /// Dies ist ein virtueller Link!!! 245 long CommunicationLinkViaSocket::DataReceived( void* EMPTYARG ) 246 { 247 { 248 vos::OGuard aGuard( aMDataReceived ); 249 nDataReceivedEventId = 0; // Achtung!! alles andere mu� oben gemacht werden. 250 } 251 return CommunicationLink::DataReceived( ); 252 } 253 254 IMPL_LINK( CommunicationLinkViaSocket, PutDataReceivedHdl, CommunicationLinkViaSocket*, EMPTYARG ) 255 { 256 nDataReceivedEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationLink, DataReceived ) ); 257 return 0; 258 } 259 260 261 262 MultiCommunicationManager::MultiCommunicationManager( sal_Bool bUseMultiChannel ) 263 : CommunicationManager( bUseMultiChannel ) 264 , bGracefullShutdown( sal_True ) 265 { 266 ActiveLinks = new CommunicationLinkList; 267 InactiveLinks = new CommunicationLinkList; 268 } 269 270 MultiCommunicationManager::~MultiCommunicationManager() 271 { 272 StopCommunication(); 273 274 if ( bGracefullShutdown ) // first try to collect all callbacks for closing channels 275 { 276 Timer aTimeout; 277 aTimeout.SetTimeout( 40000 ); 278 aTimeout.Start(); 279 sal_uInt16 nLinkCount = 0; 280 sal_uInt16 nNewLinkCount = 0; 281 while ( aTimeout.IsActive() ) 282 { 283 GetpApp()->Yield(); 284 nNewLinkCount = GetCommunicationLinkCount(); 285 if ( nNewLinkCount == 0 ) 286 aTimeout.Stop(); 287 if ( nNewLinkCount != nLinkCount ) 288 { 289 aTimeout.Start(); 290 nLinkCount = nNewLinkCount; 291 } 292 } 293 } 294 295 // Alles weghauen, was nicht rechtzeitig auf die B�ume gekommen ist 296 // Was bei StopCommunication �brig geblieben ist, da es sich asynchron austragen wollte 297 sal_uInt16 i = ActiveLinks->Count(); 298 while ( i-- ) 299 { 300 CommunicationLinkRef rTempLink = ActiveLinks->GetObject( i ); 301 ActiveLinks->Remove( i ); 302 rTempLink->InvalidateManager(); 303 rTempLink->ReleaseReference(); 304 } 305 delete ActiveLinks; 306 307 /// Die Links zwischen ConnectionClosed und Destruktor. 308 /// Hier NICHT gerefcounted, da sie sich sonst im Kreis festhaten w�rden, 309 /// da die Links sich erst in ihrem Destruktor austragen 310 i = InactiveLinks->Count(); 311 while ( i-- ) 312 { 313 CommunicationLinkRef rTempLink = InactiveLinks->GetObject( i ); 314 InactiveLinks->Remove( i ); 315 rTempLink->InvalidateManager(); 316 } 317 delete InactiveLinks; 318 } 319 320 sal_Bool MultiCommunicationManager::StopCommunication() 321 { 322 // Alle Verbindungen abbrechen 323 // ConnectionClosed entfernt die Links aus der Liste. Je nach Implementation syncron 324 // oder asyncron. Daher Von oben nach unten Abr�umen, so da� sich nichts verschiebt. 325 sal_uInt16 i = ActiveLinks->Count(); 326 int nFail = 0; 327 while ( i ) 328 { 329 if ( !ActiveLinks->GetObject(i-1)->StopCommunication() ) 330 nFail++; // Hochz�hlen, da Verbindung sich nicht (sofort) beenden l�sst. 331 i--; 332 } 333 334 return nFail == 0; 335 } 336 337 sal_Bool MultiCommunicationManager::IsLinkValid( CommunicationLink* pCL ) 338 { 339 if ( ActiveLinks->Seek_Entry( pCL ) ) 340 return sal_True; 341 else 342 return sal_False; 343 } 344 345 sal_uInt16 MultiCommunicationManager::GetCommunicationLinkCount() 346 { 347 return ActiveLinks->Count(); 348 } 349 350 CommunicationLinkRef MultiCommunicationManager::GetCommunicationLink( sal_uInt16 nNr ) 351 { 352 return ActiveLinks->GetObject( nNr ); 353 } 354 355 void MultiCommunicationManager::CallConnectionOpened( CommunicationLink* pCL ) 356 { 357 CommunicationLinkRef rHold(pCL); // H�lt den Zeiger bis zum Ende des calls 358 ActiveLinks->C40_PTR_INSERT(CommunicationLink, pCL); 359 rHold->AddRef(); 360 361 CommunicationManager::CallConnectionOpened( pCL ); 362 } 363 364 void MultiCommunicationManager::CallConnectionClosed( CommunicationLink* pCL ) 365 { 366 CommunicationLinkRef rHold(pCL); // H�lt denm Zeiger bis zum Ende des calls 367 368 CommunicationManager::CallConnectionClosed( pCL ); 369 370 sal_uInt16 nPos; 371 if ( ActiveLinks->Seek_Entry( pCL, &nPos ) ) 372 { 373 InactiveLinks->C40_PTR_INSERT(CommunicationLink, pCL); // Ohne Reference 374 ActiveLinks->Remove( nPos ); 375 } 376 pCL->ReleaseReference(); 377 378 bIsCommunicationRunning = ActiveLinks->Count() > 0; 379 // delete pCL; 380 #if OSL_DEBUG_LEVEL > 1 381 rHold->bFlag = sal_True; 382 #endif 383 } 384 385 void MultiCommunicationManager::DestroyingLink( CommunicationLink *pCL ) 386 { 387 sal_uInt16 nPos; 388 if ( InactiveLinks->Seek_Entry( pCL, &nPos ) ) 389 InactiveLinks->Remove( nPos ); 390 pCL->InvalidateManager(); 391 } 392 393 394 395 CommunicationManagerClient::CommunicationManagerClient( sal_Bool bUseMultiChannel ) 396 : MultiCommunicationManager( bUseMultiChannel ) 397 { 398 ByteString aApplication("Something inside "); 399 aApplication.Append( ByteString( DirEntry( Application::GetAppFileName() ).GetName(), gsl_getSystemTextEncoding() ) ); 400 SetApplication( aApplication ); 401 } 402 403 404 405 CommunicationManagerServerViaSocket::CommunicationManagerServerViaSocket( sal_uLong nPort, sal_uInt16 nMaxCon, sal_Bool bUseMultiChannel ) 406 : CommunicationManagerServer( bUseMultiChannel ) 407 , nPortToListen( nPort ) 408 , nMaxConnections( nMaxCon ) 409 , pAcceptThread( NULL ) 410 { 411 } 412 413 CommunicationManagerServerViaSocket::~CommunicationManagerServerViaSocket() 414 { 415 StopCommunication(); 416 } 417 418 sal_Bool CommunicationManagerServerViaSocket::StartCommunication() 419 { 420 if ( !pAcceptThread ) 421 pAcceptThread = new CommunicationManagerServerAcceptThread( this, nPortToListen, nMaxConnections ); 422 return sal_True; 423 } 424 425 426 sal_Bool CommunicationManagerServerViaSocket::StopCommunication() 427 { 428 // Erst den Acceptor anhalten 429 delete pAcceptThread; 430 pAcceptThread = NULL; 431 432 // Dann alle Verbindungen kappen 433 return CommunicationManagerServer::StopCommunication(); 434 } 435 436 437 void CommunicationManagerServerViaSocket::AddConnection( CommunicationLink *pNewConnection ) 438 { 439 CallConnectionOpened( pNewConnection ); 440 } 441 442 443 CommunicationManagerServerAcceptThread::CommunicationManagerServerAcceptThread( CommunicationManagerServerViaSocket* pServer, sal_uLong nPort, sal_uInt16 nMaxCon ) 444 : pMyServer( pServer ) 445 , pAcceptorSocket( NULL ) 446 , nPortToListen( nPort ) 447 , nMaxConnections( nMaxCon ) 448 , nAddConnectionEventId( 0 ) 449 , xmNewConnection( NULL ) 450 { 451 if ( !pMPostUserEvent ) 452 pMPostUserEvent = new vos::OMutex; 453 create(); 454 } 455 456 457 CommunicationManagerServerAcceptThread::~CommunicationManagerServerAcceptThread() 458 { 459 #ifndef aUNX // Weil das Accept nicht abgebrochen werden kann, so terminiert wenigstens das Prog 460 // #62855# pl: gilt auch bei anderen Unixen 461 // die richtige Loesung waere natuerlich, etwas auf die pipe zu schreiben, 462 // was der thread als Abbruchbedingung erkennt 463 // oder wenigstens ein kill anstatt join 464 terminate(); 465 if ( pAcceptorSocket ) 466 pAcceptorSocket->close(); // Dann das Accept unterbrechen 467 468 join(); // Warten bis fertig 469 470 if ( pAcceptorSocket ) 471 { 472 delete pAcceptorSocket; 473 pAcceptorSocket = NULL; 474 } 475 #else 476 DEBUGPRINTF ("Destructor CommunicationManagerServerAcceptThread �bersprungen!!!! (wegen Solaris BUG)\n"); 477 #endif 478 { 479 vos::OGuard aGuard( aMAddConnection ); 480 if ( nAddConnectionEventId ) 481 { 482 GetpApp()->RemoveUserEvent( nAddConnectionEventId ); 483 nAddConnectionEventId = 0; 484 CommunicationLinkRef xNewConnection = GetNewConnection(); 485 INFO_MSG( CByteString("Event gel�scht"), 486 CByteString( "AddConnectionEvent aus Queue gel�scht"), 487 CM_MISC, xNewConnection ); 488 xNewConnection->InvalidateManager(); 489 xNewConnection.Clear(); // sollte das Objekt hier l�schen 490 } 491 } 492 } 493 494 void CommunicationManagerServerAcceptThread::run() 495 { 496 if ( !nPortToListen ) 497 return; 498 499 pAcceptorSocket = new vos::OAcceptorSocket(); 500 vos::OInetSocketAddr Addr; 501 Addr.setPort( nPortToListen ); 502 pAcceptorSocket->setReuseAddr( 1 ); 503 if ( !pAcceptorSocket->bind( Addr ) ) 504 { 505 return; 506 } 507 if ( !pAcceptorSocket->listen( nMaxConnections ) ) 508 { 509 return; 510 } 511 512 513 vos::OStreamSocket *pStreamSocket = NULL; 514 515 while ( schedule() ) 516 { 517 pStreamSocket = new vos::OStreamSocket; 518 switch ( pAcceptorSocket->acceptConnection( *pStreamSocket ) ) 519 { 520 case vos::ISocketTypes::TResult_Ok: 521 { 522 pStreamSocket->setTcpNoDelay( 1 ); 523 524 TimeValue sNochEins = {0, 100}; 525 while ( schedule() && xmNewConnection.Is() ) // Solange die letzte Connection nicht abgeholt wurde warten wir 526 sleep( sNochEins ); 527 xmNewConnection = new CommunicationLinkViaSocket( pMyServer, pStreamSocket ); 528 xmNewConnection->StartCallback(); 529 { 530 vos::OGuard aGuard( aMAddConnection ); 531 vos::OGuard aGuard2( *pMPostUserEvent ); 532 nAddConnectionEventId = GetpApp()->PostUserEvent( LINK( this, CommunicationManagerServerAcceptThread, AddConnection ) ); 533 } 534 } 535 break; 536 case vos::ISocketTypes::TResult_TimedOut: 537 delete pStreamSocket; 538 pStreamSocket = NULL; 539 break; 540 case vos::ISocketTypes::TResult_Error: 541 delete pStreamSocket; 542 pStreamSocket = NULL; 543 break; 544 545 case vos::ISocketTypes::TResult_Interrupted: 546 case vos::ISocketTypes::TResult_InProgress: 547 break; // -Wall not handled... 548 } 549 } 550 } 551 552 553 IMPL_LINK( CommunicationManagerServerAcceptThread, AddConnection, void*, EMPTYARG ) 554 { 555 { 556 vos::OGuard aGuard( aMAddConnection ); 557 nAddConnectionEventId = 0; 558 } 559 pMyServer->AddConnection( xmNewConnection ); 560 xmNewConnection.Clear(); 561 return 1; 562 } 563 564 565 #define GETSET(aVar, KeyName, Dafault) \ 566 aVar = aConf.ReadKey(KeyName,"No Entry"); \ 567 if ( aVar == "No Entry" ) \ 568 { \ 569 aVar = Dafault; \ 570 aConf.WriteKey(KeyName, aVar); \ 571 } 572 573 574 CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( ByteString aHost, sal_uLong nPort, sal_Bool bUseMultiChannel ) 575 : CommunicationManagerClient( bUseMultiChannel ) 576 , aHostToTalk( aHost ) 577 , nPortToTalk( nPort ) 578 { 579 } 580 581 CommunicationManagerClientViaSocket::CommunicationManagerClientViaSocket( sal_Bool bUseMultiChannel ) 582 : CommunicationManagerClient( bUseMultiChannel ) 583 , aHostToTalk( "" ) 584 , nPortToTalk( 0 ) 585 { 586 } 587 588 CommunicationManagerClientViaSocket::~CommunicationManagerClientViaSocket() 589 { 590 } 591 592 593