blob: debe43a1cc7949744fc8aa6746ebadf5072657e3 [file] [log] [blame]
/**************************************************************
*
* 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.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sal.hxx"
# include "pipeimpl.h"
#ifndef _INC_MALLOC
# include <malloc.h>
#endif
#ifndef _INC_TCHAR
# ifdef UNICODE
# define _UNICODE
# endif
# include <tchar.h>
#endif
const TCHAR PIPE_NAME_PREFIX_MAPPING[] = TEXT("PIPE_FILE_MAPPING_");
const TCHAR PIPE_NAME_PREFIX_SYNCHRONIZE[] = TEXT("PIPE_SYNCHRONIZE_MUTEX_");
const TCHAR PIPE_NAME_PREFIX_CONNECTION[] = TEXT("PIPE_CONNECTION_SEMAPHORE_");
const DWORD PIPE_BUFFER_SIZE = 4096;
//============================================================================
// PipeData
//============================================================================
struct PipeData
{
DWORD dwProcessId;
HANDLE hReadPipe;
HANDLE hWritePipe;
};
//============================================================================
// Pipe
//============================================================================
#ifdef UNICODE
#define Pipe PipeW
#define ClientPipe ClientPipeW
#define ServerPipe ServerPipeW
#else
#define Pipe PipeA
#define ClientPipe ClientPipeA
#define ServerPipe ServerPipeA
#endif
class Pipe
{
protected:
HANDLE m_hReadPipe; // Handle to use for reading
HANDLE m_hWritePipe; // Handle to use for writing
Pipe( HANDLE hReadPipe, HANDLE hWritePipe );
static HANDLE CreatePipeDataMutex( LPCTSTR lpName, BOOL bInitialOwner );
static HANDLE CreatePipeDataMapping( LPCTSTR lpName );
static HANDLE OpenPipeDataMapping( LPCTSTR lpName );
static HANDLE CreatePipeConnectionSemaphore( LPCTSTR lpName, LONG lInitialCount, LONG lMaximumcount );
public:
Pipe( const Pipe& );
const Pipe& operator = ( const Pipe& );
virtual ~Pipe();
virtual bool Close();
virtual bool Write( LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, bool bWait = true );
virtual bool Read( LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, bool bWait = true );
virtual Pipe *AcceptConnection()
{
SetLastError( ERROR_INVALID_HANDLE );
return NULL;
}
void * operator new( size_t nBytes )
{
return HeapAlloc( GetProcessHeap(), 0, nBytes );
}
void operator delete( void *ptr )
{
HeapFree( GetProcessHeap(), 0, ptr );
}
bool is() const
{
return (FALSE != HeapValidate( GetProcessHeap(), 0, this ));
}
};
//============================================================================
// ClientPipe
//============================================================================
class ClientPipe : public Pipe
{
protected:
ClientPipe( HANDLE hReadPipe, HANDLE hWritePipe );
public:
static ClientPipe* Create( LPCTSTR lpName );
};
//============================================================================
// ServerPipe
//============================================================================
class ServerPipe : public Pipe
{
protected:
HANDLE m_hMapping;
HANDLE m_hSynchronize;
LPTSTR m_lpName;
ServerPipe( LPCTSTR lpName, HANDLE hMapping, HANDLE hSynchronize, HANDLE hReadPipe, HANDLE hWritePipe );
public:
virtual ~ServerPipe();
static ServerPipe *Create( LPCTSTR lpName );
virtual Pipe *AcceptConnection();
};
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
HANDLE Pipe::CreatePipeDataMapping( LPCTSTR lpName )
{
HANDLE hMapping = NULL;
LPTSTR lpMappingName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_MAPPING) );
if ( lpMappingName )
{
_tcscpy( lpMappingName, PIPE_NAME_PREFIX_MAPPING );
_tcscat( lpMappingName, lpName );
LPTSTR lpMappingFileName = (LPTSTR)alloca( MAX_PATH * sizeof(TCHAR) );
if ( lpMappingFileName )
{
DWORD nChars = GetTempPath( MAX_PATH, lpMappingFileName );
if ( MAX_PATH + _tcslen(lpName) < nChars + 1 )
{
lpMappingFileName = (LPTSTR)alloca( (nChars + 1 + _tcslen(lpName)) * sizeof(TCHAR) );
if ( lpMappingFileName )
nChars = GetTempPath( nChars, lpMappingFileName );
else
{
nChars = 0;
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
}
}
if ( nChars )
{
_tcscat( lpMappingFileName, lpMappingName );
HANDLE hFile = CreateFile(
lpMappingFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
NULL );
if ( IsValidHandle(hFile) )
{
hMapping = CreateFileMapping(
(HANDLE)hFile,
(LPSECURITY_ATTRIBUTES)NULL,
PAGE_READWRITE,
0,
sizeof(PipeData),
lpMappingName );
CloseHandle( hFile );
}
}
}
else
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
}
return hMapping;
}
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
HANDLE Pipe::OpenPipeDataMapping( LPCTSTR lpName )
{
HANDLE hMapping = NULL;
LPTSTR lpMappingName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_MAPPING) );
if ( lpMappingName )
{
_tcscpy( lpMappingName, PIPE_NAME_PREFIX_MAPPING );
_tcscat( lpMappingName, lpName );
hMapping = OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, lpMappingName );
}
return hMapping;
}
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
HANDLE Pipe::CreatePipeDataMutex( LPCTSTR lpName, BOOL bInitialOwner )
{
HANDLE hMutex = NULL;
LPTSTR lpMutexName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_SYNCHRONIZE) );
if ( lpMutexName )
{
_tcscpy( lpMutexName, PIPE_NAME_PREFIX_SYNCHRONIZE );
_tcscat( lpMutexName, lpName );
hMutex = CreateMutex( NULL, bInitialOwner, lpMutexName );
}
return hMutex;
}
//----------------------------------------------------------------------------
//
//----------------------------------------------------------------------------
HANDLE Pipe::CreatePipeConnectionSemaphore( LPCTSTR lpName, LONG lInitialCount, LONG lMaximumCount )
{
HANDLE hSemaphore = NULL;
LPTSTR lpSemaphoreName = (LPTSTR)alloca( _tcslen(lpName) * sizeof(TCHAR) + sizeof(PIPE_NAME_PREFIX_CONNECTION) );
if ( lpSemaphoreName )
{
_tcscpy( lpSemaphoreName, PIPE_NAME_PREFIX_CONNECTION );
_tcscat( lpSemaphoreName, lpName );
hSemaphore = CreateSemaphore( NULL, lInitialCount, lMaximumCount, lpSemaphoreName );
}
return hSemaphore;
}
//----------------------------------------------------------------------------
// Pipe copy ctor
//----------------------------------------------------------------------------
Pipe::Pipe( const Pipe& rPipe ) :
m_hReadPipe( INVALID_HANDLE_VALUE ),
m_hWritePipe( INVALID_HANDLE_VALUE )
{
DuplicateHandle(
GetCurrentProcess(),
rPipe.m_hReadPipe,
GetCurrentProcess(),
&m_hReadPipe,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
DuplicateHandle(
GetCurrentProcess(),
rPipe.m_hWritePipe,
GetCurrentProcess(),
&m_hWritePipe,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
}
//----------------------------------------------------------------------------
// Pipe assignment operator
//----------------------------------------------------------------------------
const Pipe& Pipe::operator = ( const Pipe& rPipe )
{
Close();
DuplicateHandle(
GetCurrentProcess(),
rPipe.m_hReadPipe,
GetCurrentProcess(),
&m_hReadPipe,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
DuplicateHandle(
GetCurrentProcess(),
rPipe.m_hWritePipe,
GetCurrentProcess(),
&m_hWritePipe,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
return *this;
}
//----------------------------------------------------------------------------
// Pipe ctor
//----------------------------------------------------------------------------
Pipe::Pipe( HANDLE hReadPipe, HANDLE hWritePipe ) :
m_hReadPipe( INVALID_HANDLE_VALUE ),
m_hWritePipe( INVALID_HANDLE_VALUE )
{
DuplicateHandle(
GetCurrentProcess(),
hReadPipe,
GetCurrentProcess(),
&m_hReadPipe,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
DuplicateHandle(
GetCurrentProcess(),
hWritePipe,
GetCurrentProcess(),
&m_hWritePipe,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
}
//----------------------------------------------------------------------------
// Pipe dtor
//----------------------------------------------------------------------------
Pipe::~Pipe()
{
Close();
}
//----------------------------------------------------------------------------
// Pipe Close
//----------------------------------------------------------------------------
bool Pipe::Close()
{
bool fSuccess = false; // Assume failure
if ( IsValidHandle(m_hReadPipe) )
{
CloseHandle( m_hReadPipe );
m_hReadPipe = INVALID_HANDLE_VALUE;
}
if ( IsValidHandle(m_hWritePipe) )
{
CloseHandle( m_hWritePipe );
m_hWritePipe = INVALID_HANDLE_VALUE;
}
return fSuccess;
}
//----------------------------------------------------------------------------
// Pipe Write
//----------------------------------------------------------------------------
bool Pipe::Write( LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, bool bWait )
{
DWORD dwBytesAvailable = 0;
BOOL fSuccess = TRUE;
if ( !bWait )
fSuccess = PeekNamedPipe( m_hReadPipe, NULL, 0, NULL, &dwBytesAvailable, NULL );
if ( fSuccess )
{
if ( !bWait && dwBytesToWrite > PIPE_BUFFER_SIZE - dwBytesAvailable )
dwBytesToWrite = PIPE_BUFFER_SIZE - dwBytesAvailable ;
return !!WriteFile( m_hWritePipe, lpBuffer, dwBytesToWrite, lpBytesWritten, NULL );
}
return false;
}
//----------------------------------------------------------------------------
// Pipe Read
//----------------------------------------------------------------------------
bool Pipe::Read( LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, bool bWait )
{
DWORD dwBytesAvailable = 0;
BOOL fSuccess = TRUE;
if ( !bWait )
fSuccess = PeekNamedPipe( m_hReadPipe, NULL, 0, NULL, &dwBytesAvailable, NULL );
if ( fSuccess )
{
if ( bWait || dwBytesAvailable )
return !!ReadFile( m_hReadPipe, lpBuffer, dwBytesToRead, lpBytesRead, NULL );
else
{
*lpBytesRead = 0;
return true;
}
}
return false;
}
//----------------------------------------------------------------------------
// Client pipe dtor
//----------------------------------------------------------------------------
ClientPipe::ClientPipe( HANDLE hReadPipe, HANDLE hWritePipe ) : Pipe( hReadPipe, hWritePipe )
{
}
//----------------------------------------------------------------------------
// Client pipe creation
//----------------------------------------------------------------------------
ClientPipe *ClientPipe::Create( LPCTSTR lpName )
{
ClientPipe *pPipe = NULL; // Assume failure
HANDLE hMapping = OpenPipeDataMapping( lpName );
if ( IsValidHandle(hMapping) )
{
PipeData *pData = (PipeData*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
if ( pData )
{
HANDLE hSourceProcess = OpenProcess( PROCESS_DUP_HANDLE, FALSE, pData->dwProcessId );
if ( IsValidHandle(hSourceProcess) )
{
BOOL fSuccess;
HANDLE hReadPipe = INVALID_HANDLE_VALUE, hWritePipe = INVALID_HANDLE_VALUE;
fSuccess = DuplicateHandle(
hSourceProcess,
pData->hReadPipe,
GetCurrentProcess(),
&hReadPipe,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
fSuccess = fSuccess && DuplicateHandle(
hSourceProcess,
pData->hWritePipe,
GetCurrentProcess(),
&hWritePipe,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
if ( fSuccess )
pPipe = new ClientPipe( hReadPipe, hWritePipe );
if ( IsValidHandle(hWritePipe) )
CloseHandle( hWritePipe );
if ( IsValidHandle(hReadPipe) )
CloseHandle( hReadPipe );
HANDLE hConnectionRequest = CreatePipeConnectionSemaphore( lpName, 0, 1 );
ReleaseSemaphore( hConnectionRequest, 1, NULL );
CloseHandle( hConnectionRequest );
CloseHandle( hSourceProcess );
}
UnmapViewOfFile( pData );
}
CloseHandle( hMapping );
}
return pPipe;
}
//----------------------------------------------------------------------------
// ServerPipe ctor
//----------------------------------------------------------------------------
ServerPipe::ServerPipe( LPCTSTR lpName, HANDLE hMapping, HANDLE hSynchronize, HANDLE hReadPipe, HANDLE hWritePipe ) : Pipe( hReadPipe, hWritePipe ),
m_hMapping( NULL ),
m_hSynchronize( NULL ),
m_lpName( NULL )
{
DuplicateHandle(
GetCurrentProcess(),
hMapping,
GetCurrentProcess(),
&m_hMapping,
0,
FALSE,
DUPLICATE_SAME_ACCESS );
DuplicateHandle(
GetCurrentProcess(),
hSynchronize,
GetCurrentProcess(),
&m_hSynchronize,
0,
FALSE,
DUPLICATE_SAME_ACCESS
);
m_lpName = new TCHAR[_tcslen(lpName) + 1];
if ( m_lpName )
_tcscpy( m_lpName, lpName );
}
//----------------------------------------------------------------------------
// ServerPipe dtor
//----------------------------------------------------------------------------
ServerPipe::~ServerPipe()
{
if ( IsValidHandle(m_hMapping) )
CloseHandle( m_hMapping );
if ( m_lpName )
delete[]m_lpName;
}
//----------------------------------------------------------------------------
// ServerPipe AcceptConnection
//----------------------------------------------------------------------------
Pipe *ServerPipe::AcceptConnection()
{
Pipe *pPipe = NULL; // Assume failure;
HANDLE hConnectionRequest = CreatePipeConnectionSemaphore( m_lpName, 0, 1 );
if ( WAIT_OBJECT_0 == WaitForSingleObject( hConnectionRequest, INFINITE ) )
{
pPipe = new Pipe( *this );
Close();
// Create new inbound Pipe
HANDLE hClientWritePipe = NULL, hServerReadPipe = NULL;
BOOL fSuccess = CreatePipe( &hServerReadPipe, &hClientWritePipe, NULL, PIPE_BUFFER_SIZE );
if ( fSuccess )
{
// Create outbound pipe
HANDLE hClientReadPipe = NULL, hServerWritePipe = NULL;
if ( CreatePipe( &hClientReadPipe, &hServerWritePipe, NULL, PIPE_BUFFER_SIZE ) )
{
m_hReadPipe = hServerReadPipe;
m_hWritePipe = hServerWritePipe;
PipeData *pData = (PipeData *)MapViewOfFile( m_hMapping, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(PipeData) );
HANDLE hSynchronize = CreatePipeDataMutex( m_lpName, TRUE );
CloseHandle( pData->hReadPipe );
CloseHandle( pData->hWritePipe );
pData->hReadPipe = hClientReadPipe;
pData->hWritePipe = hClientWritePipe;
ReleaseMutex( hSynchronize );
CloseHandle( hSynchronize );
}
else
{
CloseHandle( hClientWritePipe );
CloseHandle( hServerWritePipe );
}
}
ReleaseMutex( hConnectionRequest );
}
CloseHandle( hConnectionRequest );
return pPipe;
}
//----------------------------------------------------------------------------
// Pipe creation
//----------------------------------------------------------------------------
ServerPipe *ServerPipe::Create( LPCTSTR lpName )
{
ServerPipe *pPipe = NULL;
HANDLE hMapping = CreatePipeDataMapping( lpName );
if ( IsValidHandle(hMapping) )
{
if ( ERROR_FILE_EXISTS != GetLastError() )
{
HANDLE hSynchronize = CreatePipeDataMutex( lpName, FALSE);
WaitForSingleObject( hSynchronize, INFINITE );
PipeData *pData = (PipeData*)MapViewOfFile( hMapping, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
if ( pData )
{
// Initialize pipe data
pData->dwProcessId = 0;
pData->hReadPipe = NULL;
pData->hWritePipe = NULL;
// Create inbound pipe
HANDLE hServerReadPipe = NULL, hClientWritePipe = NULL;
BOOL fSuccess = CreatePipe( &hServerReadPipe, &hClientWritePipe, NULL, PIPE_BUFFER_SIZE );
if ( fSuccess )
{
// Create outbound pipe
HANDLE hServerWritePipe = NULL, hClientReadPipe = NULL;
fSuccess = CreatePipe( &hClientReadPipe, &hServerWritePipe, NULL, PIPE_BUFFER_SIZE );
if ( fSuccess )
{
pData->dwProcessId = GetCurrentProcessId();
pData->hReadPipe = hClientReadPipe;
pData->hWritePipe = hClientWritePipe;
pPipe = new ServerPipe( lpName, hMapping, hSynchronize, hServerReadPipe, hServerWritePipe );
CloseHandle( hServerWritePipe );
CloseHandle( hServerReadPipe );
}
else
{
CloseHandle( hServerReadPipe );
CloseHandle( hClientWritePipe );
}
}
UnmapViewOfFile( pData );
}
ReleaseMutex( hSynchronize );
CloseHandle( hSynchronize );
}
CloseHandle( hMapping );
}
return pPipe;
}
//----------------------------------------------------------------------------
// C style API
//----------------------------------------------------------------------------
const TCHAR LOCAL_PIPE_PREFIX[] = TEXT("\\\\.\\PIPE\\" );
extern "C" HANDLE WINAPI CreateSimplePipe( LPCTSTR lpName )
{
int nPrefixLen = _tcslen( LOCAL_PIPE_PREFIX );
if ( 0 == _tcsnicmp( lpName, LOCAL_PIPE_PREFIX, nPrefixLen ) )
lpName += nPrefixLen;
return (HANDLE)ServerPipe::Create( lpName );
}
extern "C" HANDLE WINAPI OpenSimplePipe( LPCTSTR lpName )
{
int nPrefixLen = _tcslen( LOCAL_PIPE_PREFIX );
if ( 0 == _tcsnicmp( lpName, LOCAL_PIPE_PREFIX, nPrefixLen ) )
lpName += nPrefixLen;
return (HANDLE)ClientPipe::Create( lpName );
}
extern "C" HANDLE WINAPI AcceptSimplePipeConnection( HANDLE hPipe )
{
Pipe *pPipe = (Pipe *)hPipe;
if ( pPipe->is() )
return (HANDLE)pPipe->AcceptConnection();
else
{
SetLastError( ERROR_INVALID_HANDLE );
return NULL;
}
}
extern "C" BOOL WINAPI WaitForSimplePipe( LPCTSTR /*lpName*/, DWORD /*dwTimeOut*/ )
{
return FALSE;
}
extern "C" BOOL WINAPI WriteSimplePipe( HANDLE hPipe, LPCVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten, BOOL bWait )
{
Pipe *pPipe = (Pipe *)hPipe;
if ( pPipe->is() )
return pPipe->Write( lpBuffer, dwBytesToWrite, lpBytesWritten, bWait );
else
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
}
extern "C" BOOL WINAPI ReadSimplePipe( HANDLE hPipe, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesRead, BOOL bWait )
{
Pipe *pPipe = (Pipe *)hPipe;
if ( pPipe->is() )
return pPipe->Read( lpBuffer, dwBytesToRead, lpBytesRead, bWait );
else
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
}
extern "C" BOOL WINAPI CloseSimplePipe( HANDLE hPipe )
{
Pipe *pPipe = (Pipe *)hPipe;
if ( pPipe->is() )
{
delete pPipe;
return TRUE;
}
else
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
}