| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| #include "system.h" |
| |
| #include "pipeimpl.h" |
| |
| #include <osl/pipe.h> |
| #include <osl/diagnose.h> |
| #include <osl/thread.h> |
| #include <osl/mutex.h> |
| #include <osl/semaphor.h> |
| #include <osl/conditn.h> |
| #include <osl/interlck.h> |
| #include <osl/process.h> |
| |
| #include <rtl/alloc.h> |
| #include <rtl/memory.h> |
| |
| #define PIPESYSTEM "\\\\.\\pipe\\" |
| #define PIPEPREFIX "OSL_PIPE_" |
| |
| typedef struct |
| { |
| sal_uInt32 m_Size; |
| sal_uInt32 m_ReadPos; |
| sal_uInt32 m_WritePos; |
| BYTE m_Data[1]; |
| |
| } oslPipeBuffer; |
| |
| /*****************************************************************************/ |
| /* oslPipeImpl */ |
| /*****************************************************************************/ |
| |
| struct oslPipeImpl { |
| oslInterlockedCount m_Reference; |
| HANDLE m_File; |
| HANDLE m_NamedObject; |
| PSECURITY_ATTRIBUTES m_Security; |
| HANDLE m_ReadEvent; |
| HANDLE m_WriteEvent; |
| HANDLE m_AcceptEvent; |
| rtl_uString* m_Name; |
| oslPipeError m_Error; |
| sal_Bool m_bClosed; |
| }; |
| |
| |
| /*****************************************************************************/ |
| /* osl_create/destroy-PipeImpl */ |
| /*****************************************************************************/ |
| |
| static oslInterlockedCount nPipes = 0; |
| |
| oslPipe __osl_createPipeImpl(void) |
| { |
| oslPipe pPipe; |
| |
| pPipe = (oslPipe) rtl_allocateZeroMemory(sizeof(struct oslPipeImpl)); |
| |
| pPipe->m_bClosed = sal_False; |
| pPipe->m_Reference = 0; |
| pPipe->m_Name = NULL; |
| pPipe->m_File = INVALID_HANDLE_VALUE; |
| pPipe->m_NamedObject = INVALID_HANDLE_VALUE; |
| |
| pPipe->m_ReadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); |
| pPipe->m_WriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL); |
| pPipe->m_AcceptEvent = CreateEvent(NULL, TRUE, FALSE, NULL); |
| |
| return pPipe; |
| } |
| |
| void __osl_destroyPipeImpl(oslPipe pPipe) |
| { |
| if (pPipe != NULL) |
| { |
| if ( pPipe->m_NamedObject != INVALID_HANDLE_VALUE && pPipe->m_NamedObject != NULL ) |
| CloseHandle( pPipe->m_NamedObject ); |
| |
| if (pPipe->m_Security != NULL) |
| { |
| rtl_freeMemory(pPipe->m_Security->lpSecurityDescriptor); |
| rtl_freeMemory(pPipe->m_Security); |
| } |
| |
| CloseHandle(pPipe->m_ReadEvent); |
| CloseHandle(pPipe->m_WriteEvent); |
| CloseHandle(pPipe->m_AcceptEvent); |
| |
| if (pPipe->m_Name) |
| rtl_uString_release(pPipe->m_Name); |
| |
| rtl_freeMemory(pPipe); |
| } |
| } |
| |
| |
| |
| /*****************************************************************************/ |
| /* osl_createPipe */ |
| /*****************************************************************************/ |
| oslPipe SAL_CALL osl_createPipe(rtl_uString *strPipeName, oslPipeOptions Options, |
| oslSecurity Security) |
| { |
| rtl_uString* name = NULL; |
| rtl_uString* path = NULL; |
| rtl_uString* temp = NULL; |
| oslPipe pPipe; |
| |
| PSECURITY_ATTRIBUTES pSecAttr = NULL; |
| |
| rtl_uString_newFromAscii(&path, PIPESYSTEM); |
| rtl_uString_newFromAscii(&name, PIPEPREFIX); |
| |
| if ( /*IS_NT &&*/ Security) |
| { |
| rtl_uString *Ident = NULL; |
| rtl_uString *Delim = NULL; |
| |
| OSL_VERIFY(osl_getUserIdent(Security, &Ident)); |
| rtl_uString_newFromAscii(&Delim, "_"); |
| |
| rtl_uString_newConcat(&temp, name, Ident); |
| rtl_uString_newConcat(&name, temp, Delim); |
| |
| rtl_uString_release(Ident); |
| rtl_uString_release(Delim); |
| } |
| else |
| { |
| if (Options & osl_Pipe_CREATE) |
| { |
| PSECURITY_DESCRIPTOR pSecDesc; |
| |
| pSecDesc = (PSECURITY_DESCRIPTOR) rtl_allocateMemory(SECURITY_DESCRIPTOR_MIN_LENGTH); |
| |
| /* add a NULL disc. ACL to the security descriptor */ |
| OSL_VERIFY(InitializeSecurityDescriptor(pSecDesc, SECURITY_DESCRIPTOR_REVISION)); |
| OSL_VERIFY(SetSecurityDescriptorDacl(pSecDesc, TRUE, (PACL) NULL, FALSE)); |
| |
| pSecAttr = rtl_allocateMemory(sizeof(SECURITY_ATTRIBUTES)); |
| pSecAttr->nLength = sizeof(SECURITY_ATTRIBUTES); |
| pSecAttr->lpSecurityDescriptor = pSecDesc; |
| pSecAttr->bInheritHandle = TRUE; |
| } |
| } |
| |
| rtl_uString_assign(&temp, name); |
| rtl_uString_newConcat(&name, temp, strPipeName); |
| |
| /* alloc memory */ |
| pPipe= __osl_createPipeImpl(); |
| osl_incrementInterlockedCount(&(pPipe->m_Reference)); |
| |
| /* build system pipe name */ |
| rtl_uString_assign(&temp, path); |
| rtl_uString_newConcat(&path, temp, name); |
| rtl_uString_release(temp); |
| temp = NULL; |
| |
| if (Options & osl_Pipe_CREATE) |
| { |
| SetLastError( ERROR_SUCCESS ); |
| |
| if ( IS_NT ) |
| pPipe->m_NamedObject = CreateMutexW( NULL, FALSE, name->buffer ); |
| else |
| { |
| LPSTR pszTempBuffer = NULL; |
| int nCharsNeeded; |
| |
| nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, name->buffer, name->length, NULL, 0, NULL, NULL ); |
| pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); |
| nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, name->buffer, name->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); |
| pszTempBuffer[nCharsNeeded-1] = 0; |
| |
| pPipe->m_NamedObject = CreateMutexA( NULL, FALSE, pszTempBuffer ); |
| } |
| |
| if ( pPipe->m_NamedObject != INVALID_HANDLE_VALUE && pPipe->m_NamedObject != NULL ) |
| { |
| if ( GetLastError() != ERROR_ALREADY_EXISTS ) |
| { |
| pPipe->m_Security = pSecAttr; |
| rtl_uString_assign(&pPipe->m_Name, name); |
| |
| if (IS_NT) |
| { |
| /* try to open system pipe */ |
| pPipe->m_File = CreateNamedPipeW( |
| path->buffer, |
| PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, |
| PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, |
| PIPE_UNLIMITED_INSTANCES, |
| 4096, 4096, |
| NMPWAIT_WAIT_FOREVER, |
| pPipe->m_Security); |
| |
| if (pPipe->m_File != INVALID_HANDLE_VALUE) |
| { |
| rtl_uString_release( name ); |
| rtl_uString_release( path ); |
| |
| return pPipe; |
| } |
| } |
| else /* Win 9x */ |
| { |
| LPSTR pszTempBuffer = NULL; |
| int nCharsNeeded; |
| |
| nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, NULL, 0, NULL, NULL ); |
| pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); |
| nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); |
| pszTempBuffer[nCharsNeeded-1] = 0; |
| |
| pPipe->m_File = CreateSimplePipe( pszTempBuffer ); |
| |
| if ( IsValidHandle(pPipe->m_File) ) |
| { |
| rtl_uString_release( name ); |
| rtl_uString_release( path ); |
| |
| return pPipe; |
| } |
| } |
| } |
| else |
| { |
| CloseHandle( pPipe->m_NamedObject ); |
| pPipe->m_NamedObject = INVALID_HANDLE_VALUE; |
| } |
| } |
| } |
| else |
| { |
| if (IS_NT) |
| { |
| BOOL fPipeAvailable; |
| |
| do |
| { |
| /* free instance should be available first */ |
| fPipeAvailable = WaitNamedPipeW(path->buffer, NMPWAIT_WAIT_FOREVER); |
| |
| /* first try to open system pipe */ |
| if ( fPipeAvailable ) |
| { |
| pPipe->m_File = CreateFileW( |
| path->buffer, |
| GENERIC_READ|GENERIC_WRITE, |
| FILE_SHARE_READ | FILE_SHARE_WRITE, |
| NULL, |
| OPEN_EXISTING, |
| FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, |
| NULL); |
| |
| if ( pPipe->m_File != INVALID_HANDLE_VALUE ) |
| { |
| // We got it ! |
| rtl_uString_release( name ); |
| rtl_uString_release( path ); |
| |
| return (pPipe); |
| } |
| else |
| { |
| // Pipe instance maybe catched by another client -> try again |
| } |
| } |
| } while ( fPipeAvailable ); |
| } |
| else /* Win 9x */ |
| { |
| LPSTR pszTempBuffer = NULL; |
| int nCharsNeeded; |
| |
| nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, NULL, 0, NULL, NULL ); |
| pszTempBuffer = alloca( nCharsNeeded * sizeof(CHAR) ); |
| nCharsNeeded = WideCharToMultiByte( CP_ACP, 0, path->buffer, path->length, pszTempBuffer, nCharsNeeded, NULL, NULL ); |
| pszTempBuffer[nCharsNeeded-1] = 0; |
| |
| pPipe->m_File = OpenSimplePipe( pszTempBuffer ); |
| |
| if ( IsValidHandle(pPipe->m_File) ) |
| { |
| // We got it ! |
| rtl_uString_release( name ); |
| rtl_uString_release( path ); |
| |
| return (pPipe); |
| } |
| } |
| } |
| |
| /* if we reach here something went wrong */ |
| __osl_destroyPipeImpl(pPipe); |
| |
| return NULL; |
| } |
| |
| void SAL_CALL osl_acquirePipe( oslPipe pPipe ) |
| { |
| osl_incrementInterlockedCount( &(pPipe->m_Reference) ); |
| } |
| |
| void SAL_CALL osl_releasePipe( oslPipe pPipe ) |
| { |
| // OSL_ASSERT( pPipe ); |
| |
| if( 0 == pPipe ) |
| return; |
| |
| if( 0 == osl_decrementInterlockedCount( &(pPipe->m_Reference) ) ) |
| { |
| if( ! pPipe->m_bClosed ) |
| osl_closePipe( pPipe ); |
| |
| __osl_destroyPipeImpl( pPipe ); |
| } |
| } |
| |
| void SAL_CALL osl_closePipe( oslPipe pPipe ) |
| { |
| if( pPipe && ! pPipe->m_bClosed ) |
| { |
| pPipe->m_bClosed = sal_True; |
| if (IS_NT) |
| { |
| /* if we have a system pipe close it */ |
| if (pPipe->m_File != INVALID_HANDLE_VALUE) |
| { |
| /* FlushFileBuffers(pPipe->m_File); */ |
| DisconnectNamedPipe(pPipe->m_File); |
| CloseHandle(pPipe->m_File); |
| } |
| } |
| else |
| { |
| CloseSimplePipe( pPipe->m_File ); |
| } |
| |
| } |
| } |
| |
| /*****************************************************************************/ |
| /* osl_acceptPipe */ |
| /*****************************************************************************/ |
| oslPipe SAL_CALL osl_acceptPipe(oslPipe pPipe) |
| { |
| oslPipe pAcceptedPipe = NULL; |
| |
| HANDLE Event; |
| OVERLAPPED os; |
| |
| OSL_ASSERT(pPipe); |
| |
| if (IS_NT) |
| { |
| DWORD nBytesTransfered; |
| rtl_uString* path = NULL; |
| rtl_uString* temp = NULL; |
| |
| OSL_ASSERT (pPipe->m_File != INVALID_HANDLE_VALUE); |
| |
| Event = pPipe->m_AcceptEvent; |
| rtl_zeroMemory(&os, sizeof(OVERLAPPED)); |
| os.hEvent = pPipe->m_AcceptEvent; |
| ResetEvent(pPipe->m_AcceptEvent); |
| |
| if ( !ConnectNamedPipe(pPipe->m_File, &os)) |
| { |
| switch ( GetLastError() ) |
| { |
| case ERROR_PIPE_CONNECTED: // Client already connected to pipe |
| case ERROR_NO_DATA: // Client was connected but has already closed pipe end |
| // should only appear in nonblocking mode but in fact does |
| // in blocking asynchronous mode. |
| break; |
| case ERROR_PIPE_LISTENING: // Only for nonblocking mode but see ERROR_NO_DATA |
| case ERROR_IO_PENDING: // This is normal if not client is connected yet |
| case ERROR_MORE_DATA: // Should not happen |
| // blocking call to accept |
| if( !GetOverlappedResult( pPipe->m_File, &os, &nBytesTransfered, TRUE ) ) |
| { |
| // Possible error could be that between ConnectNamedPipe and GetOverlappedResult a connect |
| // took place. |
| |
| switch ( GetLastError() ) |
| { |
| case ERROR_PIPE_CONNECTED: // Pipe was already connected |
| case ERROR_NO_DATA: // Pipe was connected but client has already closed -> ver fast client ;-) |
| break; // Everything's fine !!! |
| default: |
| // Something went wrong |
| return 0; |
| } |
| } |
| break; |
| default: // All other error say that somethings going wrong. |
| return 0; |
| } |
| } |
| |
| |
| pAcceptedPipe = __osl_createPipeImpl(); |
| OSL_ASSERT(pAcceptedPipe); |
| |
| osl_incrementInterlockedCount(&(pAcceptedPipe->m_Reference)); |
| rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name); |
| pAcceptedPipe->m_File = pPipe->m_File; |
| |
| rtl_uString_newFromAscii(&temp, PIPESYSTEM); |
| rtl_uString_newConcat(&path, temp, pPipe->m_Name); |
| rtl_uString_release(temp); |
| |
| // prepare for next accept |
| pPipe->m_File = |
| CreateNamedPipeW(path->buffer, |
| PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, |
| PIPE_WAIT | PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE, |
| PIPE_UNLIMITED_INSTANCES, |
| 4096, 4096, |
| NMPWAIT_WAIT_FOREVER, |
| pAcceptedPipe->m_Security); |
| rtl_uString_release( path ); |
| } |
| else /* Win9x */ |
| { |
| pAcceptedPipe = __osl_createPipeImpl(); |
| OSL_ASSERT(pAcceptedPipe); |
| |
| osl_incrementInterlockedCount(&(pAcceptedPipe->m_Reference)); |
| rtl_uString_assign(&pAcceptedPipe->m_Name, pPipe->m_Name); |
| pAcceptedPipe->m_File = pPipe->m_File; |
| |
| pAcceptedPipe->m_File = AcceptSimplePipeConnection( pPipe->m_File ); |
| } |
| |
| return pAcceptedPipe; |
| } |
| |
| /*****************************************************************************/ |
| /* osl_receivePipe */ |
| /*****************************************************************************/ |
| sal_Int32 SAL_CALL osl_receivePipe(oslPipe pPipe, |
| void* pBuffer, |
| sal_Int32 BytesToRead) |
| { |
| DWORD nBytes; |
| |
| OSL_ASSERT(pPipe); |
| |
| /* if we have a system pipe use it */ |
| if ( IS_NT /*pPipe->m_File != INVALID_HANDLE_VALUE*/) |
| { |
| OVERLAPPED os; |
| rtl_zeroMemory(&os,sizeof(OVERLAPPED)); |
| os.hEvent = pPipe->m_ReadEvent; |
| |
| ResetEvent(pPipe->m_ReadEvent); |
| |
| if (! ReadFile(pPipe->m_File, pBuffer, BytesToRead, &nBytes, &os) && |
| ((GetLastError() != ERROR_IO_PENDING) || |
| ! GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE))) |
| { |
| DWORD lastError = GetLastError(); |
| |
| if (lastError == ERROR_MORE_DATA) |
| nBytes = BytesToRead; |
| else |
| { |
| if (lastError == ERROR_PIPE_NOT_CONNECTED) |
| nBytes = 0; |
| else |
| nBytes = (DWORD) -1; |
| |
| pPipe->m_Error = osl_Pipe_E_ConnectionAbort; |
| } |
| } |
| } |
| else |
| { |
| BOOL fSuccess = ReadSimplePipe( pPipe->m_File, pBuffer, BytesToRead, &nBytes, TRUE ); |
| |
| if ( !fSuccess ) |
| { |
| nBytes = 0; |
| pPipe->m_Error = osl_Pipe_E_ConnectionAbort; |
| } |
| |
| } |
| |
| return (nBytes); |
| } |
| |
| /*****************************************************************************/ |
| /* osl_sendPipe */ |
| /*****************************************************************************/ |
| sal_Int32 SAL_CALL osl_sendPipe(oslPipe pPipe, |
| const void* pBuffer, |
| sal_Int32 BytesToSend) |
| { |
| DWORD nBytes; |
| OSL_ASSERT(pPipe); |
| |
| if (IS_NT/*pPipe->m_File != INVALID_HANDLE_VALUE*/) |
| { |
| OVERLAPPED os; |
| rtl_zeroMemory(&os, sizeof(OVERLAPPED)); |
| os.hEvent = pPipe->m_WriteEvent; |
| ResetEvent(pPipe->m_WriteEvent); |
| |
| if (! WriteFile(pPipe->m_File, pBuffer, BytesToSend, &nBytes, &os) && |
| ((GetLastError() != ERROR_IO_PENDING) || |
| ! GetOverlappedResult(pPipe->m_File, &os, &nBytes, TRUE))) |
| { |
| if (GetLastError() == ERROR_PIPE_NOT_CONNECTED) |
| nBytes = 0; |
| else |
| nBytes = (DWORD) -1; |
| |
| pPipe->m_Error = osl_Pipe_E_ConnectionAbort; |
| } |
| } |
| else |
| { |
| BOOL fSuccess = WriteSimplePipe( pPipe->m_File, pBuffer, BytesToSend, &nBytes, TRUE ); |
| |
| if ( !fSuccess ) |
| { |
| nBytes = 0; |
| pPipe->m_Error = osl_Pipe_E_ConnectionAbort; |
| } |
| } |
| |
| return (nBytes); |
| } |
| |
| sal_Int32 SAL_CALL osl_writePipe( oslPipe pPipe, const void *pBuffer , sal_Int32 n ) |
| { |
| /* loop until all desired bytes were send or an error occured */ |
| sal_Int32 BytesSend= 0; |
| sal_Int32 BytesToSend= n; |
| |
| OSL_ASSERT(pPipe); |
| while (BytesToSend > 0) |
| { |
| sal_Int32 RetVal; |
| |
| RetVal= osl_sendPipe(pPipe, pBuffer, BytesToSend); |
| |
| /* error occured? */ |
| if(RetVal <= 0) |
| { |
| break; |
| } |
| |
| BytesToSend -= RetVal; |
| BytesSend += RetVal; |
| pBuffer= (sal_Char*)pBuffer + RetVal; |
| } |
| |
| return BytesSend; |
| } |
| |
| sal_Int32 SAL_CALL osl_readPipe( oslPipe pPipe, void *pBuffer , sal_Int32 n ) |
| { |
| /* loop until all desired bytes were read or an error occured */ |
| sal_Int32 BytesRead= 0; |
| sal_Int32 BytesToRead= n; |
| |
| OSL_ASSERT( pPipe ); |
| while (BytesToRead > 0) |
| { |
| sal_Int32 RetVal; |
| RetVal= osl_receivePipe(pPipe, pBuffer, BytesToRead); |
| |
| /* error occured? */ |
| if(RetVal <= 0) |
| { |
| break; |
| } |
| |
| BytesToRead -= RetVal; |
| BytesRead += RetVal; |
| pBuffer= (sal_Char*)pBuffer + RetVal; |
| } |
| return BytesRead; |
| } |
| |
| |
| /*****************************************************************************/ |
| /* osl_getLastPipeError */ |
| /*****************************************************************************/ |
| oslPipeError SAL_CALL osl_getLastPipeError(oslPipe pPipe) |
| { |
| oslPipeError Error; |
| |
| if (pPipe != NULL) |
| { |
| Error = pPipe->m_Error; |
| pPipe->m_Error = osl_Pipe_E_None; |
| } |
| else |
| Error = osl_Pipe_E_NotFound; |
| |
| return (Error); |
| } |
| |