summaryrefslogtreecommitdiff
path: root/sal/osl/w32/pipe.c
diff options
context:
space:
mode:
Diffstat (limited to 'sal/osl/w32/pipe.c')
-rw-r--r--sal/osl/w32/pipe.c639
1 files changed, 639 insertions, 0 deletions
diff --git a/sal/osl/w32/pipe.c b/sal/osl/w32/pipe.c
new file mode 100644
index 000000000000..f4f893bf58c6
--- /dev/null
+++ b/sal/osl/w32/pipe.c
@@ -0,0 +1,639 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: pipe.c,v $
+ * $Revision: 1.20 $
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 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_None;
+
+ return (Error);
+}
+