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 #include "system.h" 29 30 #include "pipeimpl.h" 31 32 #include <osl/pipe.h> 33 #include <osl/diagnose.h> 34 #include <osl/thread.h> 35 #include <osl/mutex.h> 36 #include <osl/semaphor.h> 37 #include <osl/conditn.h> 38 #include <osl/interlck.h> 39 #include <osl/process.h> 40 41 #include <rtl/alloc.h> 42 #include <rtl/memory.h> 43 44 #define PIPESYSTEM "\\\\.\\pipe\\" 45 #define PIPEPREFIX "OSL_PIPE_" 46 47 typedef struct 48 { 49 sal_uInt32 m_Size; 50 sal_uInt32 m_ReadPos; 51 sal_uInt32 m_WritePos; 52 BYTE m_Data[1]; 53 54 } oslPipeBuffer; 55 56 /*****************************************************************************/ 57 /* oslPipeImpl */ 58 /*****************************************************************************/ 59 60 struct oslPipeImpl { 61 oslInterlockedCount m_Reference; 62 HANDLE m_File; 63 HANDLE m_NamedObject; 64 PSECURITY_ATTRIBUTES m_Security; 65 HANDLE m_ReadEvent; 66 HANDLE m_WriteEvent; 67 HANDLE m_AcceptEvent; 68 rtl_uString* m_Name; 69 oslPipeError m_Error; 70 sal_Bool m_bClosed; 71 }; 72 73 74 /*****************************************************************************/ 75 /* osl_create/destroy-PipeImpl */ 76 /*****************************************************************************/ 77 78 static oslInterlockedCount nPipes = 0; 79 80 oslPipe __osl_createPipeImpl(void) 81 { 82 oslPipe pPipe; 83 84 pPipe = (oslPipe) rtl_allocateZeroMemory(sizeof(struct oslPipeImpl)); 85 86 pPipe->m_bClosed = sal_False; 87 pPipe->m_Reference = 0; 88 pPipe->m_Name = NULL; 89 pPipe->m_File = INVALID_HANDLE_VALUE; 90 pPipe->m_NamedObject = INVALID_HANDLE_VALUE; 91 92 pPipe->m_ReadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 93 pPipe->m_WriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 94 pPipe->m_AcceptEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 95 96 return pPipe; 97 } 98 99 void __osl_destroyPipeImpl(oslPipe pPipe) 100 { 101 if (pPipe != NULL) 102 { 103 if ( pPipe->m_NamedObject != INVALID_HANDLE_VALUE && pPipe->m_NamedObject != NULL ) 104 CloseHandle( pPipe->m_NamedObject ); 105 106 if (pPipe->m_Security != NULL) 107 { 108 rtl_freeMemory(pPipe->m_Security->lpSecurityDescriptor); 109 rtl_freeMemory(pPipe->m_Security); 110 } 111 112 CloseHandle(pPipe->m_ReadEvent); 113 CloseHandle(pPipe->m_WriteEvent); 114 CloseHandle(pPipe->m_AcceptEvent); 115 116 if (pPipe->m_Name) 117 rtl_uString_release(pPipe->m_Name); 118 119 rtl_freeMemory(pPipe); 120 } 121 } 122 123 124 125 /*****************************************************************************/ 126 /* osl_createPipe */ 127 /*****************************************************************************/ 128 oslPipe SAL_CALL osl_createPipe(rtl_uString *strPipeName, oslPipeOptions Options, 129 oslSecurity Security) 130 { 131 rtl_uString* name = NULL; 132 rtl_uString* path = NULL; 133 rtl_uString* temp = NULL; 134 oslPipe pPipe; 135 136 PSECURITY_ATTRIBUTES pSecAttr = NULL; 137 138 rtl_uString_newFromAscii(&path, PIPESYSTEM); 139 rtl_uString_newFromAscii(&name, PIPEPREFIX); 140 141 if ( /*IS_NT &&*/ Security) 142 { 143 rtl_uString *Ident = NULL; 144 rtl_uString *Delim = NULL; 145 146 OSL_VERIFY(osl_getUserIdent(Security, &Ident)); 147 rtl_uString_newFromAscii(&Delim, "_"); 148 149 rtl_uString_newConcat(&temp, name, Ident); 150 rtl_uString_newConcat(&name, temp, Delim); 151 152 rtl_uString_release(Ident); 153 rtl_uString_release(Delim); 154 } 155 else 156 { 157 if (Options & osl_Pipe_CREATE) 158 { 159 PSECURITY_DESCRIPTOR pSecDesc; 160 161 pSecDesc = (PSECURITY_DESCRIPTOR) rtl_allocateMemory(SECURITY_DESCRIPTOR_MIN_LENGTH); 162 163 /* add a NULL disc. ACL to the security descriptor */ 164 OSL_VERIFY(InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)); 165 OSL_VERIFY(SetSecurityDescriptorDacl(pSecDesc, TRUE, (PACL) NULL, FALSE)); 166 167 pSecAttr = rtl_allocateMemory(sizeof(SECURITY_ATTRIBUTES)); 168 pSecAttr->nLength = sizeof(SECURITY_ATTRIBUTES); 169 pSecAttr->lpSecurityDescriptor = pSecDesc; 170 pSecAttr->bInheritHandle = TRUE; 171 } 172 } 173 174 rtl_uString_assign(&temp, name); 175 rtl_uString_newConcat(&name, temp, strPipeName); 176 177 /* alloc memory */ 178 pPipe= __osl_createPipeImpl(); 179 osl_incrementInterlockedCount(&(pPipe->m_Reference)); 180 181 /* build system pipe name */ 182 rtl_uString_assign(&temp, path); 183 rtl_uString_newConcat(&path, temp, name); 184 rtl_uString_release(temp); 185 temp = NULL; 186 187 if (Options & osl_Pipe_CREATE) 188 { 189 SetLastError( ERROR_SUCCESS ); 190 191 if ( IS_NT ) 192 pPipe->m_NamedObject = CreateMutexW( NULL, FALSE, name->buffer ); 193 else 194 { 195 LPSTR pszTempBuffer = NULL; 196 int nCharsNeeded; 197 198 nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, name->buffer, name->length, NULL, 0, NULL, NULL ); 199 pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); 200 nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, name->buffer, name->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); 201 pszTempBuffer[nCharsNeeded-1] = 0; 202 203 pPipe->m_NamedObject = CreateMutexA( NULL, FALSE, pszTempBuffer ); 204 } 205 206 if ( pPipe->m_NamedObject != INVALID_HANDLE_VALUE && pPipe->m_NamedObject != NULL ) 207 { 208 if ( GetLastError() != ERROR_ALREADY_EXISTS ) 209 { 210 pPipe->m_Security = pSecAttr; 211 rtl_uString_assign(&pPipe->m_Name, name); 212 213 if (IS_NT) 214 { 215 /* try to open system pipe */ 216 pPipe->m_File = CreateNamedPipeW( 217 path->buffer, 218 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 219 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 220 PIPE_UNLIMITED_INSTANCES, 221 4096, 4096, 222 NMPWAIT_WAIT_FOREVER, 223 pPipe->m_Security); 224 225 if (pPipe->m_File != INVALID_HANDLE_VALUE) 226 { 227 rtl_uString_release( name ); 228 rtl_uString_release( path ); 229 230 return pPipe; 231 } 232 } 233 else /* Win 9x */ 234 { 235 LPSTR pszTempBuffer = NULL; 236 int nCharsNeeded; 237 238 nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, NULL, 0, NULL, NULL ); 239 pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); 240 nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); 241 pszTempBuffer[nCharsNeeded-1] = 0; 242 243 pPipe->m_File = CreateSimplePipe( pszTempBuffer ); 244 245 if ( IsValidHandle(pPipe->m_File) ) 246 { 247 rtl_uString_release( name ); 248 rtl_uString_release( path ); 249 250 return pPipe; 251 } 252 } 253 } 254 else 255 { 256 CloseHandle( pPipe->m_NamedObject ); 257 pPipe->m_NamedObject = INVALID_HANDLE_VALUE; 258 } 259 } 260 } 261 else 262 { 263 if (IS_NT) 264 { 265 BOOL fPipeAvailable; 266 267 do 268 { 269 /* free instance should be available first */ 270 fPipeAvailable = WaitNamedPipeW(path->buffer, NMPWAIT_WAIT_FOREVER); 271 272 /* first try to open system pipe */ 273 if ( fPipeAvailable ) 274 { 275 pPipe->m_File = CreateFileW( 276 path->buffer, 277 GENERIC_READ|GENERIC_WRITE, 278 FILE_SHARE_READ | FILE_SHARE_WRITE, 279 NULL, 280 OPEN_EXISTING, 281 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, 282 NULL); 283 284 if ( pPipe->m_File != INVALID_HANDLE_VALUE ) 285 { 286 // We got it ! 287 rtl_uString_release( name ); 288 rtl_uString_release( path ); 289 290 return (pPipe); 291 } 292 else 293 { 294 // Pipe instance maybe catched by another client -> try again 295 } 296 } 297 } while ( fPipeAvailable ); 298 } 299 else /* Win 9x */ 300 { 301 LPSTR pszTempBuffer = NULL; 302 int nCharsNeeded; 303 304 nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, NULL, 0, NULL, NULL ); 305 pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); 306 nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); 307 pszTempBuffer[nCharsNeeded-1] = 0; 308 309 pPipe->m_File = OpenSimplePipe( pszTempBuffer ); 310 311 if ( IsValidHandle(pPipe->m_File) ) 312 { 313 // We got it ! 314 rtl_uString_release( name ); 315 rtl_uString_release( path ); 316 317 return (pPipe); 318 } 319 } 320 } 321 322 /* if we reach here something went wrong */ 323 __osl_destroyPipeImpl(pPipe); 324 325 return NULL; 326 } 327 328 void SAL_CALL osl_acquirePipe( oslPipe pPipe ) 329 { 330 osl_incrementInterlockedCount( &(pPipe->m_Reference) ); 331 } 332 333 void SAL_CALL osl_releasePipe( oslPipe pPipe ) 334 { 335 // OSL_ASSERT( pPipe ); 336 337 if( 0 == pPipe ) 338 return; 339 340 if( 0 == osl_decrementInterlockedCount( &(pPipe->m_Reference) ) ) 341 { 342 if( ! pPipe->m_bClosed ) 343 osl_closePipe( pPipe ); 344 345 __osl_destroyPipeImpl( pPipe ); 346 } 347 } 348 349 void SAL_CALL osl_closePipe( oslPipe pPipe ) 350 { 351 if( pPipe && ! pPipe->m_bClosed ) 352 { 353 pPipe->m_bClosed = sal_True; 354 if (IS_NT) 355 { 356 /* if we have a system pipe close it */ 357 if (pPipe->m_File != INVALID_HANDLE_VALUE) 358 { 359 /* FlushFileBuffers(pPipe->m_File); */ 360 DisconnectNamedPipe(pPipe->m_File); 361 CloseHandle(pPipe->m_File); 362 } 363 } 364 else 365 { 366 CloseSimplePipe( pPipe->m_File ); 367 } 368 369 } 370 } 371 372 /*****************************************************************************/ 373 /* osl_acceptPipe */ 374 /*****************************************************************************/ 375 oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe) 376 { 377 oslPipe pAcceptedPipe = NULL; 378 379 HANDLE Event; 380 OVERLAPPED os; 381 382 OSL_ASSERT(pPipe); 383 384 if (IS_NT) 385 { 386 DWORD nBytesTransfered; 387 rtl_uString* path = NULL; 388 rtl_uString* temp = NULL; 389 390 OSL_ASSERT (pPipe->m_File != INVALID_HANDLE_VALUE); 391 392 Event = pPipe->m_AcceptEvent; 393 rtl_zeroMemory(&os, sizeof(OVERLAPPED)); 394 os.hEvent = pPipe->m_AcceptEvent; 395 ResetEvent(pPipe->m_AcceptEvent); 396 397 if ( !ConnectNamedPipe(pPipe->m_File, &os)) 398 { 399 switch ( GetLastError() ) 400 { 401 case ERROR_PIPE_CONNECTED: // Client already connected to pipe 402 case ERROR_NO_DATA: // Client was connected but has already closed pipe end 403 // should only appear in nonblocking mode but in fact does 404 // in blocking asynchronous mode. 405 break; 406 case ERROR_PIPE_LISTENING: // Only for nonblocking mode but see ERROR_NO_DATA 407 case ERROR_IO_PENDING: // This is normal if not client is connected yet 408 case ERROR_MORE_DATA: // Should not happen 409 // blocking call to accept 410 if( !GetOverlappedResult( pPipe->m_File, &os, &nBytesTransfered, TRUE ) ) 411 { 412 // Possible error could be that between ConnectNamedPipe and GetOverlappedResult a connect 413 // took place. 414 415 switch ( GetLastError() ) 416 { 417 case ERROR_PIPE_CONNECTED: // Pipe was already connected 418 case ERROR_NO_DATA: // Pipe was connected but client has already closed -> ver fast client ;-) 419 break; // Everything's fine !!! 420 default: 421 // Something went wrong 422 return 0; 423 } 424 } 425 break; 426 default: // All other error say that somethings going wrong. 427 return 0; 428 } 429 } 430 431 432 pAcceptedPipe = __osl_createPipeImpl(); 433 OSL_ASSERT(pAcceptedPipe); 434 435 osl_incrementInterlockedCount(&(pAcceptedPipe->m_Reference)); 436 rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name); 437 pAcceptedPipe->m_File = pPipe->m_File; 438 439 rtl_uString_newFromAscii(&temp, PIPESYSTEM); 440 rtl_uString_newConcat(&path, temp, pPipe->m_Name); 441 rtl_uString_release(temp); 442 443 // prepare for next accept 444 pPipe->m_File = 445 CreateNamedPipeW(path->buffer, 446 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 447 PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, 448 PIPE_UNLIMITED_INSTANCES, 449 4096, 4096, 450 NMPWAIT_WAIT_FOREVER, 451 pAcceptedPipe->m_Security); 452 rtl_uString_release( path ); 453 } 454 else /* Win9x */ 455 { 456 pAcceptedPipe = __osl_createPipeImpl(); 457 OSL_ASSERT(pAcceptedPipe); 458 459 osl_incrementInterlockedCount(&(pAcceptedPipe->m_Reference)); 460 rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name); 461 pAcceptedPipe->m_File = pPipe->m_File; 462 463 pAcceptedPipe->m_File = AcceptSimplePipeConnection( pPipe->m_File ); 464 } 465 466 return pAcceptedPipe; 467 } 468 469 /*****************************************************************************/ 470 /* osl_receivePipe */ 471 /*****************************************************************************/ 472 sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe, 473 void* pBuffer, 474 sal_Int32 BytesToRead) 475 { 476 DWORD nBytes; 477 478 OSL_ASSERT(pPipe); 479 480 /* if we have a system pipe use it */ 481 if ( IS_NT /*pPipe->m_File != INVALID_HANDLE_VALUE*/) 482 { 483 OVERLAPPED os; 484 rtl_zeroMemory(&os,sizeof(OVERLAPPED)); 485 os.hEvent = pPipe->m_ReadEvent; 486 487 ResetEvent(pPipe->m_ReadEvent); 488 489 if (! ReadFile(pPipe->m_File, pBuffer, BytesToRead, &nBytes, &os) && 490 ((GetLastError() != ERROR_IO_PENDING) || 491 ! GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE))) 492 { 493 DWORD lastError = GetLastError(); 494 495 if (lastError == ERROR_MORE_DATA) 496 nBytes = BytesToRead; 497 else 498 { 499 if (lastError == ERROR_PIPE_NOT_CONNECTED) 500 nBytes = 0; 501 else 502 nBytes = (DWORD) -1; 503 504 pPipe->m_Error = osl_Pipe_E_ConnectionAbort; 505 } 506 } 507 } 508 else 509 { 510 BOOL fSuccess = ReadSimplePipe( pPipe->m_File, pBuffer, BytesToRead, &nBytes, TRUE ); 511 512 if ( !fSuccess ) 513 { 514 nBytes = 0; 515 pPipe->m_Error = osl_Pipe_E_ConnectionAbort; 516 } 517 518 } 519 520 return (nBytes); 521 } 522 523 /*****************************************************************************/ 524 /* osl_sendPipe */ 525 /*****************************************************************************/ 526 sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe, 527 const void* pBuffer, 528 sal_Int32 BytesToSend) 529 { 530 DWORD nBytes; 531 OSL_ASSERT(pPipe); 532 533 if (IS_NT/*pPipe->m_File != INVALID_HANDLE_VALUE*/) 534 { 535 OVERLAPPED os; 536 rtl_zeroMemory(&os, sizeof(OVERLAPPED)); 537 os.hEvent = pPipe->m_WriteEvent; 538 ResetEvent(pPipe->m_WriteEvent); 539 540 if (! WriteFile(pPipe->m_File, pBuffer, BytesToSend, &nBytes, &os) && 541 ((GetLastError() != ERROR_IO_PENDING) || 542 ! GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE))) 543 { 544 if (GetLastError() == ERROR_PIPE_NOT_CONNECTED) 545 nBytes = 0; 546 else 547 nBytes = (DWORD) -1; 548 549 pPipe->m_Error = osl_Pipe_E_ConnectionAbort; 550 } 551 } 552 else 553 { 554 BOOL fSuccess = WriteSimplePipe( pPipe->m_File, pBuffer, BytesToSend, &nBytes, TRUE ); 555 556 if ( !fSuccess ) 557 { 558 nBytes = 0; 559 pPipe->m_Error = osl_Pipe_E_ConnectionAbort; 560 } 561 } 562 563 return (nBytes); 564 } 565 566 sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n ) 567 { 568 /* loop until all desired bytes were send or an error occured */ 569 sal_Int32 BytesSend= 0; 570 sal_Int32 BytesToSend= n; 571 572 OSL_ASSERT(pPipe); 573 while (BytesToSend > 0) 574 { 575 sal_Int32 RetVal; 576 577 RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend); 578 579 /* error occured? */ 580 if(RetVal <= 0) 581 { 582 break; 583 } 584 585 BytesToSend -= RetVal; 586 BytesSend += RetVal; 587 pBuffer= (sal_Char*)pBuffer + RetVal; 588 } 589 590 return BytesSend; 591 } 592 593 sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n ) 594 { 595 /* loop until all desired bytes were read or an error occured */ 596 sal_Int32 BytesRead= 0; 597 sal_Int32 BytesToRead= n; 598 599 OSL_ASSERT( pPipe ); 600 while (BytesToRead > 0) 601 { 602 sal_Int32 RetVal; 603 RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead); 604 605 /* error occured? */ 606 if(RetVal <= 0) 607 { 608 break; 609 } 610 611 BytesToRead -= RetVal; 612 BytesRead += RetVal; 613 pBuffer= (sal_Char*)pBuffer + RetVal; 614 } 615 return BytesRead; 616 } 617 618 619 /*****************************************************************************/ 620 /* osl_getLastPipeError */ 621 /*****************************************************************************/ 622 oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe) 623 { 624 oslPipeError Error; 625 626 if (pPipe != NULL) 627 { 628 Error = pPipe->m_Error; 629 pPipe->m_Error = osl_Pipe_E_None; 630 } 631 else 632 Error = osl_Pipe_E_NotFound; 633 634 return (Error); 635 } 636 637