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