localipc-win.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
/* $Id$ */
/** @file
* IPRT - Local IPC, Windows Implementation Using Named Pipes.
*/
/*
* Copyright (C) 2008 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
/*
* We have to force NT 5.0 here because of
* ConvertStringSecurityDescriptorToSecurityDescriptor. Note that because of
* FILE_FLAG_FIRST_PIPE_INSTANCE this code actually requires W2K SP2+.
*/
#ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0500
#endif
#include <Windows.h>
#include <sddl.h>
#include <iprt/localipc.h>
#include <iprt/critsect.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Pipe prefix string. */
#define RTLOCALIPC_WIN_PREFIX "\\\\.\\pipe\\IPRT-"
*
* ACE format: (ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid)
*
* Note! FILE_GENERIC_WRITE (SDDL_FILE_WRITE) is evil here because it includes
* the FILE_CREATE_PIPE_INSTANCE(=FILE_APPEND_DATA) flag. Thus the hardcoded
* value 0x0012019b in the 2nd ACE. It expands to:
* 0x00000001 - FILE_READ_DATA
* 0x00000008 - FILE_READ_EA
* 0x00000080 - FILE_READ_ATTRIBUTES
* 0x00020000 - READ_CONTROL
* 0x00100000 - SYNCHRONIZE
* 0x00000002 - FILE_WRITE_DATA
* 0x00000010 - FILE_WRITE_EA
* 0x00000100 - FILE_WRITE_ATTRIBUTES
* 0x0012019b
* or FILE_GENERIC_READ | (FILE_GENERIC_WRITE & ~FILE_CREATE_PIPE_INSTANCE)
*
* @todo Double check this!
* @todo Drop the EA rights too? Since they doesn't mean anything to PIPS according to the docs.
* @todo EVERYONE -> AUTHENTICATED USERS or something more appropriate?
* @todo Have trouble allowing the owner FILE_CREATE_PIPE_INSTANCE access, so for now I'm hacking
* it just to get progress - the service runs as local system.
* The CREATOR OWNER and PERSONAL SELF works (the former is only involved in inheriting
* it seems, which is why it won't work. The latter I've no idea about. Perhaps the solution
* is to go the annoying route of OpenProcessToken, QueryTokenInformation,
* ConvertSidToStringSid and then use the result... Suggestions are very welcome
*/
#define RTLOCALIPC_WIN_SDDL \
// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_GENERIC_ALL ";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \
// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";CIOI;" SDDL_GENERIC_ALL ";;;" SDDL_CREATOR_OWNER SDDL_ACE_END
// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b" ";;;" SDDL_EVERYONE SDDL_ACE_END
// SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL ";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Local IPC service instance, Windows.
*/
typedef struct RTLOCALIPCSERVERINT
{
/** The magic (RTLOCALIPCSERVER_MAGIC). */
/** The creation flags. */
/** Critical section protecting the structure. */
/** The number of references to the instance.
* @remarks The reference counting isn't race proof. */
/** Indicates that there is a pending cancel request. */
bool volatile fCancelled;
/** The name pipe handle. */
/** The handle to the event object we're using for overlapped I/O. */
/** The overlapped I/O structure. */
/** The pipe name. */
char szName[1];
/** Pointer to a local IPC server instance (Windows). */
typedef RTLOCALIPCSERVERINT *PRTLOCALIPCSERVERINT;
/**
* Local IPC session instance, Windows.
*/
typedef struct RTLOCALIPCSESSIONINT
{
/** The magic (RTLOCALIPCSESSION_MAGIC). */
/** Critical section protecting the structure. */
/** The number of references to the instance.
* @remarks The reference counting isn't race proof. */
/** Indicates that there is a pending cancel request. */
bool volatile fCancelled;
/** The name pipe handle. */
/** The handle to the event object we're using for overlapped I/O. */
/** The overlapped I/O structure. */
/** Pointer to a local IPC session instance (Windows). */
typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/**
* Creates a named pipe instance.
*
* This is used by both RTLocalIpcServerCreate and RTLocalIpcServerListen.
*
* @returns Windows error code, that is NO_ERROR and *phNmPipe on success and some ERROR_* on failure.
*
* @param phNmPipe Where to store the named pipe handle on success. This
* will be set to INVALID_HANDLE_VALUE on failure.
* @param pszFullPipeName The full named pipe name.
* @param fFirst Set on the first call (from RTLocalIpcServerCreate), otherwise clear.
* Governs the FILE_FLAG_FIRST_PIPE_INSTANCE flag.
*/
static DWORD rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst)
{
/*
* We'll create a security descriptor from a SDDL that denies
* access to network clients (this is local IPC after all), it
* makes some further restrictions to prevent non-authenticated
* users from screwing around.
*/
#if 0 /** @todo dynamically resolve this as it is the only thing that prevents
* loading IPRT on NT4. */
&pSecDesc,
NULL))
#else
SetLastError(-1);
if (0)
#endif
{
if (fFirst)
fOpenMode, /* dwOpenMode */
PIPE_TYPE_BYTE, /* dwPipeMode */
PIPE_UNLIMITED_INSTANCES, /* nMaxInstances */
PAGE_SIZE, /* nOutBufferSize (advisory) */
PAGE_SIZE, /* nInBufferSize (ditto) */
30*1000, /* nDefaultTimeOut = 30 sec */
&SecAttrs); /* lpSecurityAttributes */
err = GetLastError();
if (hNmPipe != INVALID_HANDLE_VALUE)
{
return NO_ERROR;
}
}
else
err = GetLastError();
return err;
}
RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags)
{
/*
* Basic parameter validation.
*/
AssertReturn(fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION, VERR_NOT_IMPLEMENTED); /** @todo implement !RTLOCALIPC_FLAGS_MULTI_SESSION */
/*
* Allocate and initialize the instance data.
*/
if (!pThis)
return VERR_NO_MEMORY;
pThis->fCancelled = false;
if (RT_SUCCESS(rc))
{
pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL /*lpName*/);
{
{
return VINF_SUCCESS;
}
}
else
err = GetLastError();
}
return rc;
}
/**
* Call when the reference count reaches 0.
* Caller owns the critsect.
* @param pThis The instance to destroy.
*/
{
}
{
/*
* Validate input.
*/
if (hServer == NIL_RTLOCALIPCSERVER)
return VINF_SUCCESS;
/*
* Cancel any thread currently busy using the server,
* leaving the cleanup to it.
*/
{
}
else
return VINF_SUCCESS;
}
{
/*
* Validate input.
*/
/*
* Enter the critsect before inspecting the object further.
*/
int rc;
if (pThis->fCancelled)
{
pThis->fCancelled = false;
rc = VERR_CANCELLED;
}
else
{
/*
* Try connect a client. We need to use overlapped I/O here because
* of the cancellation a by RTLocalIpcServerCancel and RTLocalIpcServerDestroy.
*/
if ( !fRc
&& err == ERROR_IO_PENDING)
{
}
if ( !pThis->fCancelled
{
/*
* Still alive, some error or an actual client.
*
* If it's the latter we'll have to create a new pipe instance that
* replaces the current one for the server. The current pipe instance
* will be assigned to the client session.
*/
if ( fRc
|| err == ERROR_PIPE_CONNECTED)
{
{
}
else
{
/*
* We failed to create a new instance for the server, diconnect
* the client and fail. Don't try service the client here.
*/
}
}
else
}
else
{
/*
* Cancelled or destroyed.
*
* Cancel the overlapped io if it didn't complete (must be done
* in the this thread) or disconnect the client.
*/
if ( fRc
|| err == ERROR_PIPE_CONNECTED)
else if (err == ERROR_IO_PENDING)
else
rc = VERR_CANCELLED;
}
else
}
return rc;
}
{
/*
* Validate input.
*/
/*
* Enter the critical section, then set the cancellation flag
*/
return VINF_SUCCESS;
}
/**
* Create a session instance.
*
* @returns IPRT status code.
*
* @param phClientSession Where to store the session handle on success.
* @param hNmPipeSession The named pipe handle. This will be consumed by this session, meaning on failure
* to create the session it will be closed.
*/
{
int rc;
/*
* Allocate and initialize the session instance data.
*/
if (pThis)
{
pThis->fCancelled = false;
if (RT_SUCCESS(rc))
{
pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL /*lpName*/);
{
*phClientSession = pThis;
return VINF_SUCCESS;
}
/* bail out */
}
}
else
rc = VERR_NO_MEMORY;
return rc;
}
RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
{
return VINF_SUCCESS;
}
/**
* Call when the reference count reaches 0.
* Caller owns the critsect.
* @param pThis The instance to destroy.
*/
{
}
{
/*
* Validate input.
*/
if (hSession == NIL_RTLOCALIPCSESSION)
return VINF_SUCCESS;
/*
* Cancel any thread currently busy using the session,
* leaving the cleanup to it.
*/
{
}
else
return VINF_SUCCESS;
}
RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
{
return VINF_SUCCESS;
}
RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuffer, size_t cbBuffer)
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
{
RTThreadSleep(1000);
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
{
return VERR_NOT_SUPPORTED;
}
{
return VERR_NOT_SUPPORTED;
}
{
return VERR_NOT_SUPPORTED;
}