VirtualBox

Changeset 58298 in vbox


Ignore:
Timestamp:
Oct 18, 2015 7:19:52 PM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
103494
Message:

localipc-win.cpp: Fixes, improvments and cleanups. Highlights:

  • Added support for native names (i.e. you can connect to any windows specific named pipe server or create one with a windows specific name).
  • Always use W function! (my fault actually)
  • Must check for cancelling in the session code too.
  • Use rtLocalIpcWinCreateSession for both session creation scenarios so we don't forget to initialize something in one place (e.g. bounce buffer members, fortunately unused).
  • RTLocalIpcServerListen should NOT clear the cancel flag, the flag supposed to be sticky and require an explicit API method for clearing it. (Also my fault.)
  • Allow concurrent write and read threads to operate on the session instance (untested).
  • Removed the unncessary pending write wait from the Write method.
  • Commented out the bounce buffer members as we don't currently do non-blocking writes.
  • Added missing zero-byte-read completion in the Read method.
  • Only resolve the SDDL converter API once.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/win/localipc-win.cpp

    r58293 r58298  
    2929*   Header Files                                                                                                                 *
    3030*********************************************************************************************************************************/
     31#define RTMEM_WRAP_TO_EF_APIS
     32#define LOG_GROUP RTLOGGROUP_LOCALIPC
    3133/*
    3234 * We have to force NT 5.0 here because of
     
    4042# define _WIN32_WINNT 0x0500
    4143#endif
     44#define UNICODE    /* For the SDDL_ strings. */
    4245#include <Windows.h>
    4346#include <sddl.h>
    4447
    45 #include <iprt/alloc.h>
     48#include "internal/iprt.h"
     49#include <iprt/localipc.h>
     50
    4651#include <iprt/asm.h>
    4752#include <iprt/assert.h>
    4853#include <iprt/critsect.h>
     54#include <iprt/ctype.h>
    4955#include <iprt/err.h>
    5056#include <iprt/ldr.h>
    51 #include <iprt/localipc.h>
     57#include <iprt/log.h>
     58#include <iprt/mem.h>
    5259#include <iprt/param.h>
    5360#include <iprt/string.h>
     
    5663
    5764#include "internal/magics.h"
     65#include "internal-r3-win.h"
     66
    5867
    5968
     
    6271*********************************************************************************************************************************/
    6372/** Pipe prefix string. */
    64 #define RTLOCALIPC_WIN_PREFIX   "\\\\.\\pipe\\IPRT-"
     73#define RTLOCALIPC_WIN_PREFIX   L"\\\\.\\pipe\\IPRT-"
    6574
    6675/** DACL for block all network access and local users other than the creator/owner.
     
    97106#define RTLOCALIPC_WIN_SDDL_BASE \
    98107        SDDL_DACL SDDL_DELIMINATOR \
    99         SDDL_ACE_BEGIN SDDL_ACCESS_DENIED ";;" SDDL_GENERIC_ALL ";;;" SDDL_NETWORK SDDL_ACE_END \
    100         SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL ";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
     108        SDDL_ACE_BEGIN SDDL_ACCESS_DENIED L";;" SDDL_GENERIC_ALL L";;;" SDDL_NETWORK SDDL_ACE_END \
     109        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL   L";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
    101110
    102111#define RTLOCALIPC_WIN_SDDL_SERVER \
    103112        RTLOCALIPC_WIN_SDDL_BASE \
    104         SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019f"    ";;;" SDDL_EVERYONE SDDL_ACE_END
     113        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019f"   L";;;" SDDL_EVERYONE SDDL_ACE_END
    105114
    106115#define RTLOCALIPC_WIN_SDDL_CLIENT \
    107116        RTLOCALIPC_WIN_SDDL_BASE \
    108         SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b"    ";;;" SDDL_EVERYONE SDDL_ACE_END
    109 
    110 //        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_GENERIC_ALL ";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \
    111 //        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";CIOI;" SDDL_GENERIC_ALL ";;;" SDDL_CREATOR_OWNER SDDL_ACE_END
    112 //        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" "0x0012019b"    ";;;" SDDL_EVERYONE SDDL_ACE_END
    113 //        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED ";;" SDDL_FILE_ALL ";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
     117        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019b"   L";;;" SDDL_EVERYONE SDDL_ACE_END
     118
     119//        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_GENERIC_ALL L";;;" SDDL_PERSONAL_SELF SDDL_ACE_END \
     120//        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";CIOI;" SDDL_GENERIC_ALL L";;;" SDDL_CREATOR_OWNER SDDL_ACE_END
     121//        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" L"0x0012019b"    L";;;" SDDL_EVERYONE SDDL_ACE_END
     122//        SDDL_ACE_BEGIN SDDL_ACCESS_ALLOWED L";;" SDDL_FILE_ALL L";;;" SDDL_LOCAL_SYSTEM SDDL_ACE_END
    114123
    115124
     
    139148    /** The overlapped I/O structure. */
    140149    OVERLAPPED OverlappedIO;
    141     /** The pipe name. */
    142     char szName[1];
     150    /** The full pipe name (variable length). */
     151    RTUTF16 wszName[1];
    143152} RTLOCALIPCSERVERINT;
    144153/** Pointer to a local IPC server instance (Windows). */
     
    148157/**
    149158 * Local IPC session instance, Windows.
     159 *
     160 * This is a named pipe and we should probably merge the pipe code with this to
     161 * save work and code duplication.
    150162 */
    151163typedef struct RTLOCALIPCSESSIONINT
     
    158170     * @remarks The reference counting isn't race proof. */
    159171    uint32_t volatile   cRefs;
    160     /** Set if there is already pending I/O. */
    161     bool                fIOPending;
    162172    /** Set if the zero byte read that the poll code using is pending. */
    163173    bool                fZeroByteRead;
    164174    /** Indicates that there is a pending cancel request. */
    165175    bool volatile       fCancelled;
     176    /** Set if this is the server side, clear if the client. */
     177    bool                fServerSide;
    166178    /** The named pipe handle. */
    167179    HANDLE              hNmPipe;
    168     /** The handle to the event object we're using for overlapped I/O. */
    169     HANDLE              hEvent;
    170     /** The overlapped I/O structure. */
    171     OVERLAPPED          OverlappedIO;
     180    struct
     181    {
     182        RTTHREAD        hActiveThread;
     183        /** The handle to the event object we're using for overlapped I/O. */
     184        HANDLE          hEvent;
     185        /** The overlapped I/O structure. */
     186        OVERLAPPED      OverlappedIO;
     187    }
     188    /** Overlapped reads. */
     189                        Read,
     190    /** Overlapped writes. */
     191                        Write;
     192#if 0 /* Non-blocking writes are not yet supported. */
    172193    /** Bounce buffer for writes. */
    173194    uint8_t            *pbBounceBuf;
     
    176197    /** Amount of allocated buffer space. */
    177198    size_t              cbBounceBufAlloc;
     199#endif
    178200    /** Buffer for the zero byte read.
    179      *  Used in RTLocalIpcSessionWaitForData(). */
     201     * Used in RTLocalIpcSessionWaitForData(). */
    180202    uint8_t             abBuf[8];
    181203} RTLOCALIPCSESSIONINT;
     
    183205typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT;
    184206
    185 typedef BOOL WINAPI FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR(LPCTSTR, DWORD, PSECURITY_DESCRIPTOR, PULONG);
    186 typedef FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR
    187     *PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR; /* No, nobody fell on the keyboard, really! */
    188 
    189207
    190208/*********************************************************************************************************************************
    191209*   Internal Functions                                                                                                           *
    192210*********************************************************************************************************************************/
    193 static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession);
     211static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSIONINT *ppSession, HANDLE hNmPipeSession);
     212
     213
     214/*********************************************************************************************************************************
     215*   Global Variables                                                                                                             *
     216*********************************************************************************************************************************/
     217static bool volatile g_fResolvedApis = false;
     218/** advapi32.dll API ConvertStringSecurityDescriptorToSecurityDescriptorW. */
     219static decltype(ConvertStringSecurityDescriptorToSecurityDescriptorW) *g_pfnSSDLToSecDescW = NULL;
    194220
    195221
     
    204230static int rtLocalIpcServerWinAllocSecurityDescriptior(PSECURITY_DESCRIPTOR *ppDesc, bool fServer)
    205231{
    206     /** @todo Stuff this into RTInitOnce? Later. */
    207     PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR
    208         pfnConvertStringSecurityDescriptorToSecurityDescriptor = NULL;
    209 
    210     RTLDRMOD hAdvApi32 = NIL_RTLDRMOD;
    211     int rc = RTLdrLoadSystem("Advapi32.dll", true /*fNoUnload*/, &hAdvApi32);
    212     if (RT_SUCCESS(rc))
    213         rc = RTLdrGetSymbol(hAdvApi32, "ConvertStringSecurityDescriptorToSecurityDescriptorW",
    214                             (void**)&pfnConvertStringSecurityDescriptorToSecurityDescriptor);
    215 
     232    /*
     233     * Resolve the API the first time around.
     234     */
     235    if (!g_fResolvedApis)
     236    {
     237        g_pfnSSDLToSecDescW = (decltype(g_pfnSSDLToSecDescW))RTLdrGetSystemSymbol("advapi32.dll", "ConvertStringSecurityDescriptorToSecurityDescriptorW");
     238        ASMCompilerBarrier();
     239        g_fResolvedApis = true;
     240    }
     241
     242    int rc;
    216243    PSECURITY_DESCRIPTOR pSecDesc = NULL;
    217     if (RT_SUCCESS(rc))
    218     {
    219         AssertPtr(pfnConvertStringSecurityDescriptorToSecurityDescriptor);
    220 
     244    if (g_pfnSSDLToSecDescW)
     245    {
    221246        /*
    222247         * We'll create a security descriptor from a SDDL that denies
     
    225250         * users from screwing around.
    226251         */
    227         /** @todo r=bird: Why do you convert a string litteral? the 'L' prefix should
    228          *        be sufficient, shouldn't it?? */
    229         PRTUTF16 pwszSDDL;
    230         rc = RTStrToUtf16(fServer ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT, &pwszSDDL);
    231         if (RT_SUCCESS(rc))
    232         {
    233             if (!pfnConvertStringSecurityDescriptorToSecurityDescriptor((LPCTSTR)pwszSDDL,
    234                                                                         SDDL_REVISION_1,
    235                                                                         &pSecDesc,
    236                                                                         NULL))
    237             {
    238                 rc = RTErrConvertFromWin32(GetLastError());
    239             }
    240 
    241             RTUtf16Free(pwszSDDL);
    242         }
     252        PCRTUTF16 pwszSDDL = fServer ? RTLOCALIPC_WIN_SDDL_SERVER : RTLOCALIPC_WIN_SDDL_CLIENT;
     253        if (g_pfnSSDLToSecDescW(pwszSDDL, SDDL_REVISION_1, &pSecDesc, NULL))
     254        {
     255            AssertPtr(pSecDesc);
     256            *ppDesc = pSecDesc;
     257            return VINF_SUCCESS;
     258        }
     259
     260        rc = RTErrConvertFromWin32(GetLastError());
    243261    }
    244262    else
     
    248266        rc = VERR_NOT_SUPPORTED;
    249267    }
    250 
    251     if (hAdvApi32 != NIL_RTLDRMOD)
    252          RTLdrClose(hAdvApi32);
    253 
    254     if (RT_SUCCESS(rc))
    255     {
    256         AssertPtr(pSecDesc);
    257         *ppDesc = pSecDesc;
    258     }
    259 
    260268    return rc;
    261269}
    262270
     271
    263272/**
    264273 * Creates a named pipe instance.
     
    267276 *
    268277 * @return  IPRT status code.
    269  * @param   phNmPipe            Where to store the named pipe handle on success. This
    270  *                              will be set to INVALID_HANDLE_VALUE on failure.
    271  * @param   pszFullPipeName     The full named pipe name.
    272  * @param   fFirst              Set on the first call (from RTLocalIpcServerCreate), otherwise clear.
    273  *                              Governs the FILE_FLAG_FIRST_PIPE_INSTANCE flag.
    274  */
    275 static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst)
     278 * @param   phNmPipe        Where to store the named pipe handle on success.
     279 *                          This will be set to INVALID_HANDLE_VALUE on failure.
     280 * @param   pwszPipeName    The named pipe name, full, UTF-16 encoded.
     281 * @param   fFirst          Set on the first call (from RTLocalIpcServerCreate),
     282 *                          otherwise clear. Governs the
     283 *                          FILE_FLAG_FIRST_PIPE_INSTANCE flag.
     284 */
     285static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, PCRTUTF16 pwszPipeName, bool fFirst)
    276286{
    277287    *phNmPipe = INVALID_HANDLE_VALUE;
     
    282292    {
    283293        SECURITY_ATTRIBUTES SecAttrs;
    284         SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
     294        SecAttrs.nLength              = sizeof(SECURITY_ATTRIBUTES);
    285295        SecAttrs.lpSecurityDescriptor = pSecDesc;
    286         SecAttrs.bInheritHandle = FALSE;
     296        SecAttrs.bInheritHandle       = FALSE;
    287297
    288298        DWORD fOpenMode = PIPE_ACCESS_DUPLEX
    289299                        | PIPE_WAIT
    290300                        | FILE_FLAG_OVERLAPPED;
    291 
    292         bool fSupportsFirstInstance = false;
    293 
    294         OSVERSIONINFOEX OSInfoEx;
    295         RT_ZERO(OSInfoEx);
    296         OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
    297         if (   GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
    298             && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT)
    299         {
    300             if (   /* Vista+. */
    301                    OSInfoEx.dwMajorVersion >= 6
    302                    /* Windows XP+. */
    303                 || (   OSInfoEx.dwMajorVersion == 5
    304                     && OSInfoEx.dwMinorVersion >  0)
    305                    /* Windows 2000. */
    306                 || (   OSInfoEx.dwMajorVersion == 5
    307                     && OSInfoEx.dwMinorVersion == 0
    308                     && OSInfoEx.wServicePackMajor >= 2))
    309             {
    310                 /* Requires at least W2K (5.0) SP2+. This is non-fatal. */
    311                 fSupportsFirstInstance = true;
    312             }
    313         }
    314 
    315         if (fFirst && fSupportsFirstInstance)
    316             fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
    317 
    318         HANDLE hNmPipe = CreateNamedPipe(pszFullPipeName,               /* lpName */
    319                                          fOpenMode,                     /* dwOpenMode */
    320                                          PIPE_TYPE_BYTE,                /* dwPipeMode */
    321                                          PIPE_UNLIMITED_INSTANCES,      /* nMaxInstances */
    322                                          PAGE_SIZE,                     /* nOutBufferSize (advisory) */
    323                                          PAGE_SIZE,                     /* nInBufferSize (ditto) */
    324                                          30*1000,                       /* nDefaultTimeOut = 30 sec */
    325                                          &SecAttrs);                    /* lpSecurityAttributes */
     301        if (   fFirst
     302            && (   g_enmWinVer >= kRTWinOSType_XP
     303                || (   g_enmWinVer == kRTWinOSType_2K
     304                    && g_WinOsInfoEx.wServicePackMajor >= 2) ) )
     305            fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; /* Introduced with W2K SP2 */
     306
     307        HANDLE hNmPipe = CreateNamedPipeW(pwszPipeName,                  /* lpName */
     308                                          fOpenMode,                     /* dwOpenMode */
     309                                          PIPE_TYPE_BYTE,                /* dwPipeMode */
     310                                          PIPE_UNLIMITED_INSTANCES,      /* nMaxInstances */
     311                                          PAGE_SIZE,                     /* nOutBufferSize (advisory) */
     312                                          PAGE_SIZE,                     /* nInBufferSize (ditto) */
     313                                          30*1000,                       /* nDefaultTimeOut = 30 sec */
     314                                          &SecAttrs);                    /* lpSecurityAttributes */
    326315        LocalFree(pSecDesc);
    327316        if (hNmPipe != INVALID_HANDLE_VALUE)
    328         {
    329317            *phNmPipe = hNmPipe;
    330         }
    331318        else
    332319            rc = RTErrConvertFromWin32(GetLastError());
     
    337324
    338325
     326/**
     327 * Validates the user specified name.
     328 *
     329 * @returns IPRT status code.
     330 * @param   pszName         The name to validate.
     331 * @param   pcwcFullName    Where to return the UTF-16 length of the full name.
     332 * @param   fNative         Whether it's a native name or a portable name.
     333 */
     334static int rtLocalIpcWinValidateName(const char *pszName, size_t *pcwcFullName, bool fNative)
     335{
     336    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
     337    AssertReturn(*pszName, VERR_INVALID_NAME);
     338
     339    if (!fNative)
     340    {
     341        size_t cwcName = RT_ELEMENTS(RTLOCALIPC_WIN_PREFIX) - 1;
     342        for (;;)
     343        {
     344            char ch = *pszName++;
     345            if (!ch)
     346                break;
     347            AssertReturn(!RT_C_IS_CNTRL(ch), VERR_INVALID_NAME);
     348            AssertReturn((unsigned)ch < 0x80, VERR_INVALID_NAME);
     349            AssertReturn(ch != '\\', VERR_INVALID_NAME);
     350            AssertReturn(ch != '/', VERR_INVALID_NAME);
     351            cwcName++;
     352        }
     353        *pcwcFullName = cwcName;
     354    }
     355    else
     356    {
     357        int rc = RTStrCalcUtf16LenEx(pszName, RTSTR_MAX, pcwcFullName);
     358        AssertRCReturn(rc, rc);
     359    }
     360
     361    return VINF_SUCCESS;
     362}
     363
     364
     365/**
     366 * Constructs the full pipe name as UTF-16.
     367 *
     368 * @returns IPRT status code.
     369 * @param   pszName         The user supplied name.
     370 * @param   pwszFullName    The output buffer.
     371 * @param   cwcFullName     The output buffer size excluding the terminator.
     372 * @param   fNative         Whether the user supplied name is a native or
     373 *                          portable one.
     374 */
     375static int rtLocalIpcWinConstructName(const char *pszName, PRTUTF16 pwszFullName, size_t cwcFullName, bool fNative)
     376{
     377    if (!fNative)
     378    {
     379        static RTUTF16 const s_wszPrefix[] = RTLOCALIPC_WIN_PREFIX;
     380        Assert(cwcFullName * sizeof(RTUTF16) > sizeof(s_wszPrefix));
     381        memcpy(pwszFullName, s_wszPrefix, sizeof(s_wszPrefix));
     382        cwcFullName  -= RT_ELEMENTS(s_wszPrefix) - 1;
     383        pwszFullName += RT_ELEMENTS(s_wszPrefix) - 1;
     384    }
     385    return RTStrToUtf16Ex(pszName, RTSTR_MAX, &pwszFullName, cwcFullName + 1, NULL);
     386}
     387
     388
    339389RTDECL(int) RTLocalIpcServerCreate(PRTLOCALIPCSERVER phServer, const char *pszName, uint32_t fFlags)
    340390{
    341391    /*
    342      * Basic parameter validation.
     392     * Validate parameters.
    343393     */
    344394    AssertPtrReturn(phServer, VERR_INVALID_POINTER);
    345395
    346396    AssertReturn(!(fFlags & ~RTLOCALIPC_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
    347     AssertReturn(fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION, VERR_INVALID_FLAGS); /** @todo Implement !RTLOCALIPC_FLAGS_MULTI_SESSION */
    348 
    349     AssertPtrReturn(pszName, VERR_INVALID_POINTER);
    350     AssertReturn(*pszName, VERR_INVALID_NAME);
    351 
    352     /*
    353      * Allocate and initialize the instance data.
    354      *
    355      * We align the size on pointer size here to make sure we get naturally
    356      * aligned members in the critsect when the electric fence heap is active.
    357      */
    358     size_t cchName = strlen(pszName);
    359     size_t cbThis = RT_OFFSETOF(RTLOCALIPCSERVERINT, szName[cchName + sizeof(RTLOCALIPC_WIN_PREFIX)]);
    360     PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAllocVar(cbThis);
    361     if (!pThis)
    362         return VERR_NO_MEMORY;
    363     pThis->u32Magic = RTLOCALIPCSERVER_MAGIC;
    364     pThis->cRefs = 1; /* the one we return */
    365     pThis->fCancelled = false;
    366     memcpy(pThis->szName, RTLOCALIPC_WIN_PREFIX, sizeof(RTLOCALIPC_WIN_PREFIX) - 1);
    367     memcpy(&pThis->szName[sizeof(RTLOCALIPC_WIN_PREFIX) - 1], pszName, cchName + 1);
    368     int rc = RTCritSectInit(&pThis->CritSect);
     397    AssertReturn(fFlags & RTLOCALIPC_FLAGS_MULTI_SESSION, VERR_NOT_IMPLEMENTED); /** @todo Implement !RTLOCALIPC_FLAGS_MULTI_SESSION */
     398
     399    size_t cwcFullName;
     400    int rc = rtLocalIpcWinValidateName(pszName, &cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME));
    369401    if (RT_SUCCESS(rc))
    370402    {
    371         pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
    372                                     FALSE /*bInitialState*/, NULL /*lpName*/);
    373         if (pThis->hEvent != NULL)
    374         {
    375             RT_ZERO(pThis->OverlappedIO);
    376             pThis->OverlappedIO.Internal = STATUS_PENDING;
    377             pThis->OverlappedIO.hEvent = pThis->hEvent;
    378 
    379             rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe,
    380                                                        pThis->szName, true /* fFirst */);
     403        /*
     404         * Allocate and initialize the instance data.
     405         */
     406        size_t cbThis = RT_OFFSETOF(RTLOCALIPCSERVERINT, wszName[cwcFullName + 1]);
     407        PRTLOCALIPCSERVERINT pThis = (PRTLOCALIPCSERVERINT)RTMemAllocVar(cbThis);
     408        AssertReturn(pThis, VERR_NO_MEMORY);
     409
     410        pThis->u32Magic   = RTLOCALIPCSERVER_MAGIC;
     411        pThis->cRefs      = 1; /* the one we return */
     412        pThis->fCancelled = false;
     413
     414        rc = rtLocalIpcWinConstructName(pszName, pThis->wszName, cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_FLAGS_NATIVE_NAME));
     415        if (RT_SUCCESS(rc))
     416        {
     417            rc = RTCritSectInit(&pThis->CritSect);
    381418            if (RT_SUCCESS(rc))
    382419            {
    383                 *phServer = pThis;
    384                 return VINF_SUCCESS;
     420                pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
     421                                            FALSE /*bInitialState*/, NULL /*lpName*/);
     422                if (pThis->hEvent != NULL)
     423                {
     424                    RT_ZERO(pThis->OverlappedIO);
     425                    pThis->OverlappedIO.Internal = STATUS_PENDING;
     426                    pThis->OverlappedIO.hEvent   = pThis->hEvent;
     427
     428                    rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe, pThis->wszName, true /* fFirst */);
     429                    if (RT_SUCCESS(rc))
     430                    {
     431                        *phServer = pThis;
     432                        return VINF_SUCCESS;
     433                    }
     434
     435                    BOOL fRc = CloseHandle(pThis->hEvent);
     436                    AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
     437                }
     438                else
     439                    rc = RTErrConvertFromWin32(GetLastError());
     440
     441                int rc2 = RTCritSectDelete(&pThis->CritSect);
     442                AssertRC(rc2);
    385443            }
    386 
    387             BOOL fRc = CloseHandle(pThis->hEvent);
    388             AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    389         }
    390         else
    391             rc = RTErrConvertFromWin32(GetLastError());
    392 
    393         int rc2 = RTCritSectDelete(&pThis->CritSect);
    394         AssertRC(rc2);
    395     }
    396     RTMemFree(pThis);
     444        }
     445        RTMemFree(pThis);
     446    }
    397447    return rc;
     448}
     449
     450
     451/**
     452 * Retains a reference to the server instance.
     453 *
     454 * @returns
     455 * @param   pThis               The server instance.
     456 */
     457DECLINLINE(void) rtLocalIpcServerRetain(PRTLOCALIPCSERVERINT pThis)
     458{
     459    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     460    Assert(cRefs < UINT32_MAX / 2 && cRefs);
    398461}
    399462
     
    407470 * @param   pThis       The instance to destroy.
    408471 */
    409 static int rtLocalIpcServerWinDestroy(PRTLOCALIPCSERVERINT pThis)
    410 {
     472DECL_NO_INLINE(static, int) rtLocalIpcServerWinDestroy(PRTLOCALIPCSERVERINT pThis)
     473{
     474    Assert(pThis->u32Magic == ~RTLOCALIPCSERVER_MAGIC);
     475    pThis->u32Magic = ~RTLOCALIPCSERVER_MAGIC;
     476
    411477    BOOL fRc = CloseHandle(pThis->hNmPipe);
    412478    AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
     
    423489    return VINF_OBJECT_DESTROYED;
    424490}
     491
     492
     493/**
     494 * Server instance destructor.
     495 *
     496 * @returns VINF_OBJECT_DESTROYED
     497 * @param   pThis               The server instance.
     498 */
     499DECL_NO_INLINE(static, int) rtLocalIpcServerDtor(PRTLOCALIPCSERVERINT pThis)
     500{
     501    RTCritSectEnter(&pThis->CritSect);
     502    return rtLocalIpcServerWinDestroy(pThis);
     503}
     504
     505
     506/**
     507 * Releases a reference to the server instance.
     508 *
     509 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed.
     510 * @param   pThis               The server instance.
     511 */
     512DECLINLINE(int) rtLocalIpcServerRelease(PRTLOCALIPCSERVERINT pThis)
     513{
     514    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     515    Assert(cRefs < UINT32_MAX / 2);
     516    if (!cRefs)
     517        return rtLocalIpcServerDtor(pThis);
     518    return VINF_SUCCESS;
     519}
     520
     521
     522/**
     523 * Releases a reference to the server instance and leaves the critsect.
     524 *
     525 * @returns VINF_SUCCESS if only release, VINF_OBJECT_DESTROYED if destroyed.
     526 * @param   pThis               The server instance.
     527 */
     528DECLINLINE(int) rtLocalIpcServerReleaseAndUnlock(PRTLOCALIPCSERVERINT pThis)
     529{
     530    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     531    Assert(cRefs < UINT32_MAX / 2);
     532    if (!cRefs)
     533        return rtLocalIpcServerWinDestroy(pThis);
     534    return RTCritSectLeave(&pThis->CritSect);
     535}
     536
    425537
    426538
     
    440552     * leaving the cleanup to it.
    441553     */
     554    AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC, RTLOCALIPCSERVER_MAGIC), VERR_WRONG_ORDER);
     555
    442556    RTCritSectEnter(&pThis->CritSect);
    443     ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSERVER_MAGIC);
     557
     558    /* Cancel everything. */
    444559    ASMAtomicUoWriteBool(&pThis->fCancelled, true);
    445     Assert(pThis->cRefs);
    446     pThis->cRefs--;
    447 
    448     if (pThis->cRefs)
     560    if (pThis->cRefs > 1)
    449561    {
    450562        BOOL fRc = SetEvent(pThis->hEvent);
    451563        AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    452 
    453         RTCritSectLeave(&pThis->CritSect);
    454     }
    455     else
    456         return rtLocalIpcServerWinDestroy(pThis);
    457     return VINF_SUCCESS;
     564    }
     565
     566    return rtLocalIpcServerReleaseAndUnlock(pThis);
    458567}
    459568
     
    467576    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
    468577    AssertReturn(pThis->u32Magic == RTLOCALIPCSERVER_MAGIC, VERR_INVALID_HANDLE);
     578    AssertPtrReturn(phClientSession, VERR_INVALID_POINTER);
    469579
    470580    /*
    471581     * Enter the critsect before inspecting the object further.
    472582     */
    473     int rc;
    474     RTCritSectEnter(&pThis->CritSect);
    475     if (pThis->fCancelled)
    476     {
    477         pThis->fCancelled = false;
    478         rc = VERR_CANCELLED;
    479         RTCritSectLeave(&pThis->CritSect);
    480     }
    481     else
    482     {
    483         pThis->cRefs++;
     583    int rc = RTCritSectEnter(&pThis->CritSect);
     584    AssertRCReturn(rc, rc);
     585
     586    rtLocalIpcServerRetain(pThis);
     587    if (!pThis->fCancelled)
     588    {
    484589        ResetEvent(pThis->hEvent);
     590
    485591        RTCritSectLeave(&pThis->CritSect);
    486592
     
    516622            {
    517623                HANDLE hNmPipe;
    518                 rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->szName, false /* fFirst */);
     624                rc = rtLocalIpcServerWinCreatePipeInstance(&hNmPipe, pThis->wszName, false /* fFirst */);
    519625                if (RT_SUCCESS(rc))
    520626                {
     
    539645        {
    540646            /*
    541              * Cancelled or destroyed.
     647             * Cancelled.
    542648             *
    543649             * Cancel the overlapped io if it didn't complete (must be done
    544650             * in the this thread) or disconnect the client.
    545651             */
     652            Assert(pThis->fCancelled);
    546653            if (    fRc
    547654                ||  dwErr == ERROR_PIPE_CONNECTED)
     
    554661            rc = VERR_CANCELLED;
    555662        }
    556 
    557         pThis->cRefs--;
    558         if (pThis->cRefs)
    559             RTCritSectLeave(&pThis->CritSect);
    560         else
    561             rtLocalIpcServerWinDestroy(pThis);
    562     }
    563 
     663    }
     664    else
     665    {
     666        /*pThis->fCancelled = false; - Terrible interface idea. Add API to clear fCancelled if ever required. */
     667        rc = VERR_CANCELLED;
     668    }
     669    rtLocalIpcServerReleaseAndUnlock(pThis);
    564670    return rc;
    565671}
     
    579685     * and signal the event (to wake up anyone in/at WaitForSingleObject).
    580686     */
     687    rtLocalIpcServerRetain(pThis);
    581688    int rc = RTCritSectEnter(&pThis->CritSect);
    582689    if (RT_SUCCESS(rc))
    583690    {
    584691        ASMAtomicUoWriteBool(&pThis->fCancelled, true);
     692
    585693        BOOL fRc = SetEvent(pThis->hEvent);
    586         AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    587 
    588         rc = RTCritSectLeave(&pThis->CritSect);
    589     }
    590 
     694        if (fRc)
     695            rc = VINF_SUCCESS;
     696        else
     697        {
     698            DWORD dwErr = GetLastError();
     699            AssertMsgFailed(("dwErr=%u\n", dwErr));
     700            rc = RTErrConvertFromWin32(dwErr);
     701        }
     702
     703        rtLocalIpcServerReleaseAndUnlock(pThis);
     704    }
     705    else
     706        rtLocalIpcServerRelease(pThis);
    591707    return rc;
    592708}
     
    594710
    595711/**
    596  * Create a session instance.
     712 * Create a session instance for a new server client or a client connect.
    597713 *
    598714 * @returns IPRT status code.
    599715 *
    600  * @param   phClientSession         Where to store the session handle on success.
    601  * @param   hNmPipeSession          The named pipe handle. This will be consumed by this session, meaning on failure
    602  *                                  to create the session it will be closed.
    603  */
    604 static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession)
    605 {
    606     AssertPtrReturn(phClientSession, VERR_INVALID_POINTER);
    607     AssertReturn(hNmPipeSession != INVALID_HANDLE_VALUE, VERR_INVALID_HANDLE);
    608 
    609     int rc;
     716 * @param   ppSession       Where to store the session handle on success.
     717 * @param   hNmPipeSession  The named pipe handle if server calling,
     718 *                          INVALID_HANDLE_VALUE if client connect.  This will
     719 *                          be consumed by this session, meaning on failure to
     720 *                          create the session it will be closed.
     721 */
     722static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSIONINT *ppSession, HANDLE hNmPipeSession)
     723{
     724    AssertPtr(ppSession);
    610725
    611726    /*
    612727     * Allocate and initialize the session instance data.
    613728     */
    614     PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis));
     729    int rc;
     730    PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAllocZ(sizeof(*pThis));
    615731    if (pThis)
    616732    {
    617         pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
    618         pThis->cRefs = 1; /* our ref */
    619         pThis->fCancelled = false;
    620         pThis->fIOPending = false;
    621         pThis->fZeroByteRead = false;
    622         pThis->hNmPipe = hNmPipeSession;
    623 
     733        pThis->u32Magic         = RTLOCALIPCSESSION_MAGIC;
     734        pThis->cRefs            = 1; /* our ref */
     735        pThis->fCancelled       = false;
     736        pThis->fZeroByteRead    = false;
     737        pThis->fServerSide      = hNmPipeSession != INVALID_HANDLE_VALUE;
     738        pThis->hNmPipe          = hNmPipeSession;
     739#if 0 /* Non-blocking writes are not yet supported. */
     740        pThis->pbBounceBuf      = NULL;
     741        pThis->cbBounceBufAlloc = 0;
     742        pThis->cbBounceBufUsed  = 0;
     743#endif
    624744        rc = RTCritSectInit(&pThis->CritSect);
    625745        if (RT_SUCCESS(rc))
    626746        {
    627             pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
    628                                         FALSE /*bInitialState*/, NULL /*lpName*/);
    629             if (pThis->hEvent != NULL)
     747            pThis->Read.hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
     748                                             FALSE /*bInitialState*/, NULL /*lpName*/);
     749            if (pThis->Read.hEvent != NULL)
    630750            {
    631                 RT_ZERO(pThis->OverlappedIO);
    632                 pThis->OverlappedIO.Internal = STATUS_PENDING;
    633                 pThis->OverlappedIO.hEvent = pThis->hEvent;
    634 
    635                 *phClientSession = pThis;
    636                 return VINF_SUCCESS;
     751                pThis->Read.OverlappedIO.Internal = STATUS_PENDING;
     752                pThis->Read.OverlappedIO.hEvent   = pThis->Read.hEvent;
     753                pThis->Read.hActiveThread         = NIL_RTTHREAD;
     754
     755                pThis->Write.hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
     756                                                  FALSE /*bInitialState*/, NULL /*lpName*/);
     757                if (pThis->Write.hEvent != NULL)
     758                {
     759                    pThis->Write.OverlappedIO.Internal = STATUS_PENDING;
     760                    pThis->Write.OverlappedIO.hEvent   = pThis->Write.hEvent;
     761                    pThis->Write.hActiveThread         = NIL_RTTHREAD;
     762
     763                    *ppSession = pThis;
     764                    return VINF_SUCCESS;
     765                }
     766
     767                CloseHandle(pThis->Read.hEvent);
    637768            }
    638769
     
    646777        rc = VERR_NO_MEMORY;
    647778
    648     BOOL fRc = CloseHandle(hNmPipeSession);
    649     AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
     779    if (hNmPipeSession != INVALID_HANDLE_VALUE)
     780    {
     781        BOOL fRc = CloseHandle(hNmPipeSession);
     782        AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
     783    }
    650784    return rc;
    651785}
    652786
     787
    653788RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
    654789{
     790    /*
     791     * Validate input.
     792     */
    655793    AssertPtrReturn(phSession, VERR_INVALID_POINTER);
    656     AssertPtrReturn(pszName, VERR_INVALID_POINTER);
    657     AssertReturn(*pszName, VERR_INVALID_NAME);
    658     AssertReturn(!fFlags, VERR_INVALID_FLAGS); /* Flags currently unused, must be 0. */
    659 
    660     PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis));
    661     if (!pThis)
    662         return VERR_NO_MEMORY;
    663 
    664     pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
    665     pThis->cRefs = 1; /* The one we return. */
    666     pThis->fIOPending = false;
    667     pThis->fZeroByteRead = false;
    668     pThis->fCancelled = false;
    669     pThis->pbBounceBuf = NULL;
    670     pThis->cbBounceBufAlloc = 0;
    671     pThis->cbBounceBufUsed = 0;
    672 
    673     int rc = RTCritSectInit(&pThis->CritSect);
     794    AssertReturn(!(fFlags & ~RTLOCALIPC_C_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
     795
     796    size_t cwcFullName;
     797    int rc = rtLocalIpcWinValidateName(pszName, &cwcFullName, RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
    674798    if (RT_SUCCESS(rc))
    675799    {
    676         pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
    677                                     FALSE /*bInitialState*/, NULL /*lpName*/);
    678         if (pThis->hEvent != NULL)
    679         {
    680             RT_ZERO(pThis->OverlappedIO);
    681             pThis->OverlappedIO.Internal = STATUS_PENDING;
    682             pThis->OverlappedIO.hEvent = pThis->hEvent;
    683 
     800        /*
     801         * Create a session (shared with server client session creation).
     802         */
     803        PRTLOCALIPCSESSIONINT pThis;
     804        rc = rtLocalIpcWinCreateSession(&pThis, INVALID_HANDLE_VALUE);
     805        if (RT_SUCCESS(rc))
     806        {
     807            /*
     808             * Try open the pipe.
     809             */
    684810            PSECURITY_DESCRIPTOR pSecDesc;
    685             rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc, false /* Client */);
     811            rc = rtLocalIpcServerWinAllocSecurityDescriptior(&pSecDesc, false /*fServer*/);
    686812            if (RT_SUCCESS(rc))
    687813            {
    688                 char *pszPipe;
    689                 if (RTStrAPrintf(&pszPipe, "%s%s", RTLOCALIPC_WIN_PREFIX, pszName))
     814                PRTUTF16 pwszFullName = RTUtf16Alloc((cwcFullName + 1) * sizeof(RTUTF16));
     815                if (pwszFullName)
     816                    rc = rtLocalIpcWinConstructName(pszName, pwszFullName, cwcFullName,
     817                                                    RT_BOOL(fFlags & RTLOCALIPC_C_FLAGS_NATIVE_NAME));
     818                else
     819                    rc = VERR_NO_UTF16_MEMORY;
     820                if (RT_SUCCESS(rc))
    690821                {
    691822                    SECURITY_ATTRIBUTES SecAttrs;
    692                     SecAttrs.nLength = sizeof(SECURITY_ATTRIBUTES);
     823                    SecAttrs.nLength              = sizeof(SECURITY_ATTRIBUTES);
    693824                    SecAttrs.lpSecurityDescriptor = pSecDesc;
    694                     SecAttrs.bInheritHandle = FALSE;
    695 
    696                     HANDLE hPipe = CreateFile(pszPipe,                  /* pipe name */
    697                                                 GENERIC_READ            /* read and write access */
    698                                               | GENERIC_WRITE,
    699                                               0,                        /* no sharing */
    700                                               &SecAttrs,                /* lpSecurityAttributes */
    701                                               OPEN_EXISTING,            /* opens existing pipe */
    702                                               FILE_FLAG_OVERLAPPED,     /* default attributes */
    703                                               NULL);                    /* no template file */
    704                     RTStrFree(pszPipe);
    705 
     825                    SecAttrs.bInheritHandle       = FALSE;
     826
     827                    HANDLE hPipe = CreateFileW(pwszFullName,
     828                                               GENERIC_READ | GENERIC_WRITE,
     829                                               0 /*no sharing*/,
     830                                               &SecAttrs,
     831                                               OPEN_EXISTING,
     832                                               FILE_FLAG_OVERLAPPED,
     833                                               NULL /*no template hanlde*/);
    706834                    if (hPipe != INVALID_HANDLE_VALUE)
    707835                    {
     836                        pThis->hNmPipe = hPipe;
     837
    708838                        LocalFree(pSecDesc);
    709 
    710                         pThis->hNmPipe = hPipe;
     839                        RTUtf16Free(pwszFullName);
     840
     841                        /*
     842                         * We're done!
     843                         */
    711844                        *phSession = pThis;
    712845                        return VINF_SUCCESS;
    713846                    }
    714                     else
    715                         rc = RTErrConvertFromWin32(GetLastError());
     847
     848                    rc = RTErrConvertFromWin32(GetLastError());
    716849                }
    717                 else
    718                     rc = VERR_NO_MEMORY;
    719 
     850
     851                RTUtf16Free(pwszFullName);
    720852                LocalFree(pSecDesc);
    721853            }
    722854
    723             BOOL fRc = CloseHandle(pThis->hEvent);
    724             AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    725         }
    726         else
    727             rc = RTErrConvertFromWin32(GetLastError());
    728 
    729         int rc2 = RTCritSectDelete(&pThis->CritSect);
    730         AssertRC(rc2);
    731     }
    732 
    733     RTMemFree(pThis);
     855            /* destroy the session handle. */
     856            CloseHandle(pThis->Read.hEvent);
     857            CloseHandle(pThis->Write.hEvent);
     858            RTCritSectDelete(&pThis->CritSect);
     859
     860            RTMemFree(pThis);
     861        }
     862    }
    734863    return rc;
     864}
     865
     866
     867/**
     868 * Cancells all pending I/O operations, forcing the methods to return with
     869 * VERR_CANCELLED (unless they've got actual data to return).
     870 *
     871 * Used by RTLocalIpcSessionCancel and RTLocalIpcSessionClose.
     872 *
     873 * @returns IPRT status code.
     874 * @param   pThis               The client session instance.
     875 */
     876static int rtLocalIpcWinCancel(PRTLOCALIPCSESSIONINT pThis)
     877{
     878    ASMAtomicUoWriteBool(&pThis->fCancelled, true);
     879
     880    /*
     881     * Call CancelIo since this call cancels both read and write oriented operations.
     882     */
     883    if (   pThis->fZeroByteRead
     884        || pThis->Read.hActiveThread != NIL_RTTHREAD
     885        || pThis->Write.hActiveThread != NIL_RTTHREAD)
     886        CancelIo(pThis->hNmPipe);
     887
     888    /*
     889     * Set both event semaphores.
     890     */
     891    BOOL fRc = SetEvent(pThis->Read.hEvent);
     892    AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
     893    fRc = SetEvent(pThis->Write.hEvent);
     894    AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
     895
     896    return VINF_SUCCESS;
     897}
     898
     899
     900/**
     901 * Retains a reference to the session instance.
     902 *
     903 * @param   pThis               The client session instance.
     904 */
     905DECLINLINE(void) rtLocalIpcSessionRetain(PRTLOCALIPCSESSIONINT pThis)
     906{
     907    uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
     908    Assert(cRefs < UINT32_MAX / 2 && cRefs);
    735909}
    736910
     
    744918 * @param   pThis       The instance to destroy.
    745919 */
    746 static int rtLocalIpcSessionWinDestroy(PRTLOCALIPCSESSIONINT pThis)
     920DECL_NO_INLINE(static, int) rtLocalIpcSessionWinDestroy(PRTLOCALIPCSESSIONINT pThis)
    747921{
    748922    BOOL fRc = CloseHandle(pThis->hNmPipe);
     
    750924    pThis->hNmPipe = INVALID_HANDLE_VALUE;
    751925
    752     fRc = CloseHandle(pThis->hEvent);
    753     AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    754     pThis->hEvent = NULL;
    755 
    756     RTCritSectLeave(&pThis->CritSect);
     926    fRc = CloseHandle(pThis->Write.hEvent);
     927    AssertMsg(fRc, ("%d\n", GetLastError()));
     928    pThis->Write.hEvent = NULL;
     929
     930    fRc = CloseHandle(pThis->Read.hEvent);
     931    AssertMsg(fRc, ("%d\n", GetLastError()));
     932    pThis->Read.hEvent = NULL;
     933
     934    int rc2 = RTCritSectLeave(&pThis->CritSect); AssertRC(rc2);
    757935    RTCritSectDelete(&pThis->CritSect);
    758936
    759937    RTMemFree(pThis);
    760938    return VINF_OBJECT_DESTROYED;
     939}
     940
     941
     942/**
     943 * Session instance destructor.
     944 *
     945 * @returns VINF_OBJECT_DESTROYED
     946 * @param   pThis               The server instance.
     947 */
     948DECL_NO_INLINE(static, int) rtLocalIpcSessionDtor(PRTLOCALIPCSESSIONINT pThis)
     949{
     950    RTCritSectEnter(&pThis->CritSect);
     951    return rtLocalIpcSessionWinDestroy(pThis);
     952}
     953
     954
     955/**
     956 * Releases a reference to the session instance.
     957 *
     958 * @returns VINF_SUCCESS or VINF_OBJECT_DESTROYED as appropriate.
     959 * @param   pThis               The session instance.
     960 */
     961DECLINLINE(int) rtLocalIpcSessionRelease(PRTLOCALIPCSESSIONINT pThis)
     962{
     963    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     964    Assert(cRefs < UINT32_MAX / 2);
     965    if (!cRefs)
     966        return rtLocalIpcSessionDtor(pThis);
     967    Log(("rtLocalIpcSessionRelease: %u refs left\n", cRefs));
     968    return VINF_SUCCESS;
     969}
     970
     971
     972/**
     973 * Releases a reference to the session instance and unlock it.
     974 *
     975 * @returns VINF_SUCCESS or VINF_OBJECT_DESTROYED as appropriate.
     976 * @param   pThis               The session instance.
     977 */
     978DECLINLINE(int) rtLocalIpcSessionReleaseAndUnlock(PRTLOCALIPCSESSIONINT pThis)
     979{
     980    uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
     981    Assert(cRefs < UINT32_MAX / 2);
     982    if (!cRefs)
     983        return rtLocalIpcSessionWinDestroy(pThis);
     984
     985    int rc2 = RTCritSectLeave(&pThis->CritSect); AssertRC(rc2);
     986    Log(("rtLocalIpcSessionRelease: %u refs left\n", cRefs));
     987    return VINF_SUCCESS;
    761988}
    762989
     
    7741001
    7751002    /*
    776      * Cancel any thread currently busy using the session,
    777      * leaving the cleanup to it.
     1003     * Invalidate the instance, cancel all outstanding I/O and drop our reference.
    7781004     */
     1005    AssertReturn(ASMAtomicCmpXchgU32(&pThis->u32Magic, ~RTLOCALIPCSESSION_MAGIC, RTLOCALIPCSESSION_MAGIC), VERR_WRONG_ORDER);
     1006
    7791007    RTCritSectEnter(&pThis->CritSect);
    780     ASMAtomicUoWriteU32(&pThis->u32Magic, ~RTLOCALIPCSESSION_MAGIC);
    781     ASMAtomicUoWriteBool(&pThis->fCancelled, true);
    782     pThis->cRefs--;
    783 
    784     if (pThis->cRefs > 0)
    785     {
    786         BOOL fRc = SetEvent(pThis->hEvent);
    787         AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    788 
    789         RTCritSectLeave(&pThis->CritSect);
     1008    rtLocalIpcWinCancel(pThis);
     1009    return rtLocalIpcSessionReleaseAndUnlock(pThis);
     1010}
     1011
     1012
     1013/**
     1014 * Handles WaitForSingleObject return value when waiting for a zero byte read.
     1015 *
     1016 * The zero byte read is started by the RTLocalIpcSessionWaitForData method and
     1017 * left pending when the function times out.  This saves us the problem of
     1018 * CancelIo messing with all active I/O operations and the trouble of restarting
     1019 * the zero byte read the next time the method is called.  However should
     1020 * RTLocalIpcSessionRead be called after a failed RTLocalIpcSessionWaitForData
     1021 * call, the zero byte read will still be pending and it must wait for it to
     1022 * complete before the OVERLAPPEDIO structure can be reused.
     1023 *
     1024 * Thus, both functions will do WaitForSingleObject and share this routine to
     1025 * handle the outcome.
     1026 *
     1027 * @returns IPRT status code.
     1028 * @param   pThis               The session instance.
     1029 * @param   rcWait              The WaitForSingleObject return code.
     1030 */
     1031static int rtLocalIpcWinGetZeroReadResult(PRTLOCALIPCSESSIONINT pThis, DWORD rcWait)
     1032{
     1033    int rc;
     1034    DWORD cbRead = 42;
     1035    if (rcWait == WAIT_OBJECT_0)
     1036    {
     1037        if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, !pThis->fCancelled /*fWait*/))
     1038        {
     1039            Assert(cbRead == 0);
     1040            rc = VINF_SUCCESS;
     1041            pThis->fZeroByteRead = false;
     1042        }
     1043        else if (pThis->fCancelled)
     1044            rc = VERR_CANCELLED;
     1045        else
     1046            rc = RTErrConvertFromWin32(GetLastError());
    7901047    }
    7911048    else
    792         return rtLocalIpcSessionWinDestroy(pThis);
    793     return VINF_SUCCESS;
     1049    {
     1050        /* We try get the result here too, just in case we're lucky, but no waiting. */
     1051        DWORD dwErr = GetLastError();
     1052        if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead, FALSE /*fWait*/))
     1053        {
     1054            Assert(cbRead == 0);
     1055            rc = VINF_SUCCESS;
     1056            pThis->fZeroByteRead = false;
     1057        }
     1058        else if (rcWait == WAIT_TIMEOUT)
     1059            rc = VERR_TIMEOUT;
     1060        else if (rcWait == WAIT_ABANDONED)
     1061            rc = VERR_INVALID_HANDLE;
     1062        else
     1063            rc = RTErrConvertFromWin32(dwErr);
     1064    }
     1065    return rc;
    7941066}
    7951067
     
    8061078    if (RT_SUCCESS(rc))
    8071079    {
    808         /* No concurrent readers, sorry. */
    809         if (pThis->cRefs == 1)
    810         {
    811             pThis->cRefs++;
     1080        rtLocalIpcSessionRetain(pThis);
     1081        if (pThis->Read.hActiveThread == NIL_RTTHREAD)
     1082        {
     1083            pThis->Read.hActiveThread = RTThreadSelf();
     1084            Assert(!pThis->fZeroByteRead);
    8121085
    8131086            size_t cbTotalRead = 0;
    8141087            while (cbToRead > 0)
    8151088            {
    816                 /*
    817                  * Kick of a an overlapped read.  It should return immediately if
    818                  * there is bytes in the buffer.  If not, we'll cancel it and see
    819                  * what we get back.
    820                  */
    821                 rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
    8221089                DWORD cbRead = 0;
    823                 pThis->fIOPending = true;
    824                 RTCritSectLeave(&pThis->CritSect);
    825 
    826                 if (ReadFile(pThis->hNmPipe, pvBuf,
    827                              cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
    828                              &cbRead, &pThis->OverlappedIO))
    829                     rc = VINF_SUCCESS;
    830                 else if (GetLastError() == ERROR_IO_PENDING)
     1090                if (!pThis->fCancelled)
    8311091                {
    832                     WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
    833                     if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO,
    834                                             &cbRead, TRUE /*fWait*/))
    835                         rc = VINF_SUCCESS;
     1092                    /*
     1093                     * Wait for pending zero byte read, if necessary.
     1094                     * Note! It cannot easily be cancelled due to concurrent current writes.
     1095                     */
     1096                    if (!pThis->fZeroByteRead)
     1097                    { /* likely */ }
    8361098                    else
    8371099                    {
    838                         DWORD dwErr = GetLastError();
    839                         AssertMsgFailed(("err=%ld\n",  dwErr));
    840                         rc = RTErrConvertFromWin32(dwErr);
     1100                        RTCritSectLeave(&pThis->CritSect);
     1101                        DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, RT_MS_1MIN);
     1102                        RTCritSectEnter(&pThis->CritSect);
     1103
     1104                        rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait);
     1105                        if (RT_SUCCESS(rc) || rc == VERR_TIMEOUT)
     1106                            continue;
     1107                        break;
     1108                    }
     1109
     1110                    /*
     1111                     * Kick of a an overlapped read.  It should return immediately if
     1112                     * there is bytes in the buffer.  If not, we'll cancel it and see
     1113                     * what we get back.
     1114                     */
     1115                    rc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(rc == TRUE);
     1116                    RTCritSectLeave(&pThis->CritSect);
     1117
     1118                    if (ReadFile(pThis->hNmPipe, pvBuf,
     1119                                 cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
     1120                                 &cbRead, &pThis->Read.OverlappedIO))
     1121                    {
     1122                        RTCritSectEnter(&pThis->CritSect);
     1123                        rc = VINF_SUCCESS;
     1124                    }
     1125                    else if (GetLastError() == ERROR_IO_PENDING)
     1126                    {
     1127                        DWORD rcWait = WaitForSingleObject(pThis->Read.OverlappedIO.hEvent, INFINITE);
     1128
     1129                        RTCritSectEnter(&pThis->CritSect);
     1130                        if (GetOverlappedResult(pThis->hNmPipe, &pThis->Read.OverlappedIO, &cbRead,
     1131                                                rcWait == WAIT_OBJECT_0 && !pThis->fCancelled /*fWait*/))
     1132                            rc = VINF_SUCCESS;
     1133                        else
     1134                        {
     1135                            if (pThis->fCancelled)
     1136                                rc = VERR_CANCELLED;
     1137                            else
     1138                                rc = RTErrConvertFromWin32(GetLastError());
     1139                            break;
     1140                        }
     1141                    }
     1142                    else
     1143                    {
     1144                        rc = RTErrConvertFromWin32(GetLastError());
     1145                        AssertMsgFailedBreak(("%Rrc\n", rc));
    8411146                    }
    8421147                }
    8431148                else
    8441149                {
    845                     DWORD dwErr = GetLastError();
    846                     AssertMsgFailed(("err2=%ld\n",  dwErr));
    847                     rc = RTErrConvertFromWin32(dwErr);
     1150                    rc = VERR_CANCELLED;
     1151                    break;
    8481152                }
    849 
    850                 RTCritSectEnter(&pThis->CritSect);
    851                 pThis->fIOPending = false;
    852                 if (RT_FAILURE(rc))
    853                     break;
    8541153
    8551154                /* Advance. */
     
    8681167            }
    8691168
    870             pThis->cRefs--;
     1169            pThis->Read.hActiveThread = NIL_RTTHREAD;
    8711170        }
    8721171        else
    8731172            rc = VERR_WRONG_ORDER;
    874         RTCritSectLeave(&pThis->CritSect);
     1173        rtLocalIpcSessionReleaseAndUnlock(pThis);
    8751174    }
    8761175
     
    8791178
    8801179
     1180#if 0 /* Non-blocking writes are not yet supported. */
    8811181/**
    8821182 * Common worker for handling I/O completion.
     
    8901190{
    8911191    int rc;
    892     DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0);
    893     if (dwRc == WAIT_OBJECT_0)
     1192    DWORD rcWait = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0);
     1193    if (rcWait == WAIT_OBJECT_0)
    8941194    {
    8951195        DWORD cbWritten = 0;
     
    9331233        }
    9341234    }
    935     else if (dwRc == WAIT_TIMEOUT)
     1235    else if (rcWait == WAIT_TIMEOUT)
    9361236        rc = VINF_TRY_AGAIN;
    9371237    else
    9381238    {
    9391239        pThis->fIOPending = false;
    940         if (dwRc == WAIT_ABANDONED)
     1240        if (rcWait == WAIT_ABANDONED)
    9411241            rc = VERR_INVALID_HANDLE;
    9421242        else
     
    9451245    return rc;
    9461246}
     1247#endif
    9471248
    9481249
     
    9581259    if (RT_SUCCESS(rc))
    9591260    {
    960         /* No concurrent writers, sorry. */
    961         if (pThis->cRefs == 1)
    962         {
    963             pThis->cRefs++;
     1261        rtLocalIpcSessionRetain(pThis);
     1262        if (pThis->Write.hActiveThread == NIL_RTTHREAD)
     1263        {
     1264            pThis->Write.hActiveThread = RTThreadSelf();
    9641265
    9651266            /*
    966              * If I/O is pending, wait for it to complete.
     1267             * Try write everything. No bounce buffering necessary.
    9671268             */
    968             if (pThis->fIOPending)
     1269            size_t cbTotalWritten = 0;
     1270            while (cbToWrite > 0)
    9691271            {
    970                 rc = rtLocalIpcSessionWriteCheckCompletion(pThis);
    971                 while (rc == VINF_TRY_AGAIN)
     1272                DWORD cbWritten = 0;
     1273                if (!pThis->fCancelled)
    9721274                {
    973                     Assert(pThis->fIOPending);
    974                     HANDLE hEvent = pThis->OverlappedIO.hEvent;
     1275                    BOOL fRc = ResetEvent(pThis->Write.OverlappedIO.hEvent); Assert(fRc == TRUE);
    9751276                    RTCritSectLeave(&pThis->CritSect);
    976                     WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
    977                     RTCritSectEnter(&pThis->CritSect);
    978                 }
    979             }
    980             if (RT_SUCCESS(rc))
    981             {
    982                 Assert(!pThis->fIOPending);
    983 
    984                 /*
    985                  * Try write everything.
    986                  * No bounce buffering, cUsers protects us.
    987                  */
    988                 size_t cbTotalWritten = 0;
    989                 while (cbToWrite > 0)
    990                 {
    991                     BOOL fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE);
    992                     pThis->fIOPending = true;
    993                     RTCritSectLeave(&pThis->CritSect);
    994 
    995                     DWORD cbWritten = 0;
     1277
    9961278                    fRc = WriteFile(pThis->hNmPipe, pvBuf,
    9971279                                    cbToWrite <= ~(DWORD)0 ? (DWORD)cbToWrite : ~(DWORD)0,
    998                                     &cbWritten, &pThis->OverlappedIO);
     1280                                    &cbWritten, &pThis->Write.OverlappedIO);
    9991281                    if (fRc)
    1000                     {
    10011282                        rc = VINF_SUCCESS;
    1002                     }
    10031283                    else
    10041284                    {
     
    10061286                        if (dwErr == ERROR_IO_PENDING)
    10071287                        {
    1008                             DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
    1009                             if (dwRc == WAIT_OBJECT_0)
     1288                            DWORD rcWait = WaitForSingleObject(pThis->Write.OverlappedIO.hEvent, INFINITE);
     1289                            if (rcWait == WAIT_OBJECT_0)
    10101290                            {
    1011                                 if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE /*fWait*/))
     1291                                if (GetOverlappedResult(pThis->hNmPipe, &pThis->Write.OverlappedIO, &cbWritten, TRUE /*fWait*/))
    10121292                                    rc = VINF_SUCCESS;
    10131293                                else
    10141294                                    rc = RTErrConvertFromWin32(GetLastError());
    10151295                            }
    1016                             else if (dwRc == WAIT_TIMEOUT)
     1296                            else if (rcWait == WAIT_TIMEOUT)
    10171297                                rc = VERR_TIMEOUT;
    1018                             else if (dwRc == WAIT_ABANDONED)
     1298                            else if (rcWait == WAIT_ABANDONED)
    10191299                                rc = VERR_INVALID_HANDLE;
    10201300                            else
     
    10281308
    10291309                    RTCritSectEnter(&pThis->CritSect);
    1030                     pThis->fIOPending = false;
    10311310                    if (RT_FAILURE(rc))
    10321311                        break;
    1033 
    1034                     /* Advance. */
    1035                     pvBuf           = (char const *)pvBuf + cbWritten;
    1036                     cbTotalWritten += cbWritten;
    1037                     cbToWrite      -= cbWritten;
    10381312                }
     1313                else
     1314                {
     1315                    rc = VERR_CANCELLED;
     1316                    break;
     1317                }
     1318
     1319                /* Advance. */
     1320                pvBuf           = (char const *)pvBuf + cbWritten;
     1321                cbTotalWritten += cbWritten;
     1322                cbToWrite      -= cbWritten;
    10391323            }
    10401324
    1041             pThis->cRefs--;
     1325            pThis->Write.hActiveThread = NIL_RTTHREAD;
     1326        }
     1327        else
     1328            rc = VERR_WRONG_ORDER;
     1329        rtLocalIpcSessionReleaseAndUnlock(pThis);
     1330    }
     1331
     1332    return rc;
     1333}
     1334
     1335
     1336RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
     1337{
     1338    PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)hSession;
     1339    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     1340    AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
     1341
     1342    int rc = RTCritSectEnter(&pThis->CritSect);
     1343    if (RT_SUCCESS(rc))
     1344    {
     1345        if (pThis->Write.hActiveThread == NIL_RTTHREAD)
     1346        {
     1347            /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until
     1348             * all data was written (or an error occurred). */
     1349            /** @todo r=bird: above comment is misinformed.
     1350            /*        Implement this as soon as we want an explicit asynchronous version of
     1351             *        RTLocalIpcSessionWrite on Windows. */
     1352            rc = VINF_SUCCESS;
    10421353        }
    10431354        else
     
    10451356        RTCritSectLeave(&pThis->CritSect);
    10461357    }
    1047 
    10481358    return rc;
    1049 }
    1050 
    1051 
    1052 RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
    1053 {
    1054     /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until
    1055      * all data was written (or an error occurred). */
    1056     /** @todo Implement this as soon as we want an explicit asynchronous version of
    1057      *        RTLocalIpcSessionWrite on Windows. */
    1058     return VINF_SUCCESS;
    10591359}
    10601360
     
    10661366    AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
    10671367
    1068     uint64_t const StartMsTS = RTTimeMilliTS();
     1368    uint64_t const msStart = RTTimeMilliTS();
    10691369
    10701370    int rc = RTCritSectEnter(&pThis->CritSect);
    1071     if (RT_FAILURE(rc))
    1072         return rc;
    1073     for (unsigned iLoop = 0;; iLoop++)
    1074     {
    1075         HANDLE hWait = INVALID_HANDLE_VALUE;
    1076 
    1077         if (pThis->fIOPending)
    1078             hWait = pThis->OverlappedIO.hEvent;
    1079         else
    1080         {
    1081             /* Peek at the pipe buffer and see how many bytes it contains. */
    1082             DWORD cbAvailable;
    1083             BOOL fRc = PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL);
    1084             if (   fRc
    1085                 && cbAvailable)
     1371    if (RT_SUCCESS(rc))
     1372    {
     1373        rtLocalIpcSessionRetain(pThis);
     1374        if (pThis->Read.hActiveThread == NIL_RTTHREAD)
     1375        {
     1376            pThis->Read.hActiveThread = RTThreadSelf();
     1377
     1378            /*
     1379             * Wait loop.
     1380             */
     1381            for (unsigned iLoop = 0;; iLoop++)
    10861382            {
    1087                 rc = VINF_SUCCESS;
    1088                 break;
    1089             }
    1090             else if (!fRc)
    1091             {
    1092                 rc = RTErrConvertFromWin32(GetLastError());
    1093                 break;
    1094             }
    1095 
    1096             /* Start a zero byte read operation that we can wait on. */
    1097             if (cMillies == 0)
    1098             {
    1099                 rc = VERR_TIMEOUT;
    1100                 break;
    1101             }
    1102             AssertBreakStmt(pThis->cRefs == 1, rc = VERR_WRONG_ORDER);
    1103             fRc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(fRc == TRUE);
    1104             DWORD cbRead = 0;
    1105             if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0, &cbRead, &pThis->OverlappedIO))
    1106             {
    1107                 rc = VINF_SUCCESS;
    1108                 if (iLoop > 10)
    1109                     RTThreadYield();
    1110             }
    1111             else if (GetLastError() == ERROR_IO_PENDING)
    1112             {
    1113                 pThis->cRefs++;
    1114                 pThis->fIOPending = true;
    1115                 pThis->fZeroByteRead = true;
    1116                 hWait = pThis->OverlappedIO.hEvent;
    1117             }
    1118             else
    1119                 rc = RTErrConvertFromWin32(GetLastError());
    1120         }
    1121 
    1122         if (RT_FAILURE(rc))
    1123             break;
    1124 
    1125         /*
    1126          * Check for timeout.
    1127          */
    1128         DWORD cMsMaxWait = INFINITE;
    1129         if (   cMillies != RT_INDEFINITE_WAIT
    1130             && (   hWait != INVALID_HANDLE_VALUE
    1131                 || iLoop > 10)
    1132            )
    1133         {
    1134             uint64_t cElapsed = RTTimeMilliTS() - StartMsTS;
    1135             if (cElapsed >= cMillies)
    1136             {
    1137                 rc = VERR_TIMEOUT;
    1138                 break;
    1139             }
    1140             cMsMaxWait = cMillies - (uint32_t)cElapsed;
    1141         }
    1142 
    1143         /*
    1144          * Wait.
    1145          */
    1146         if (hWait != INVALID_HANDLE_VALUE)
    1147         {
    1148             RTCritSectLeave(&pThis->CritSect);
    1149 
    1150             DWORD dwRc = WaitForSingleObject(hWait, cMsMaxWait);
    1151             if (dwRc == WAIT_OBJECT_0)
    1152                 rc = VINF_SUCCESS;
    1153             else if (dwRc == WAIT_TIMEOUT)
    1154                 rc = VERR_TIMEOUT;
    1155             else if (dwRc == WAIT_ABANDONED)
    1156                 rc = VERR_INVALID_HANDLE;
    1157             else
    1158                 rc = RTErrConvertFromWin32(GetLastError());
    1159 
    1160             if (   RT_FAILURE(rc)
    1161                 && pThis->u32Magic != RTLOCALIPCSESSION_MAGIC)
    1162                 return rc;
    1163 
    1164             int rc2 = RTCritSectEnter(&pThis->CritSect);
    1165             AssertRC(rc2);
    1166             if (pThis->fZeroByteRead)
    1167             {
    1168                 Assert(pThis->cRefs);
    1169                 pThis->cRefs--;
    1170                 pThis->fIOPending = false;
    1171 
    1172                 if (rc != VINF_SUCCESS)
     1383                /*
     1384                 * Check for cancellation before we continue.
     1385                 */
     1386                if (!pThis->fCancelled)
     1387                { /* likely */ }
     1388                else
    11731389                {
    1174                     BOOL fRc = CancelIo(pThis->hNmPipe);
    1175                     Assert(fRc == TRUE);
     1390                    rc = VERR_CANCELLED;
     1391                    break;
    11761392                }
    11771393
    1178                 DWORD cbRead = 0;
    1179                 BOOL fRc = GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbRead, TRUE /*fWait*/);
    1180                 if (   !fRc
    1181                     && RT_SUCCESS(rc))
     1394                /*
     1395                 * Prep something we can wait on.
     1396                 */
     1397                HANDLE hWait = INVALID_HANDLE_VALUE;
     1398                if (pThis->fZeroByteRead)
     1399                    hWait = pThis->Read.OverlappedIO.hEvent;
     1400                else
    11821401                {
    1183                     DWORD dwRc = GetLastError();
    1184                     if (dwRc == ERROR_OPERATION_ABORTED)
    1185                         rc = VERR_CANCELLED;
     1402                    /* Peek at the pipe buffer and see how many bytes it contains. */
     1403                    DWORD cbAvailable;
     1404                    if (   PeekNamedPipe(pThis->hNmPipe, NULL, 0, NULL, &cbAvailable, NULL)
     1405                        && cbAvailable)
     1406                    {
     1407                        rc = VINF_SUCCESS;
     1408                        break;
     1409                    }
     1410
     1411                    /* Start a zero byte read operation that we can wait on. */
     1412                    if (cMillies == 0)
     1413                    {
     1414                        rc = VERR_TIMEOUT;
     1415                        break;
     1416                    }
     1417                    BOOL fRc = ResetEvent(pThis->Read.OverlappedIO.hEvent); Assert(fRc == TRUE);
     1418                    DWORD cbRead = 0;
     1419                    if (ReadFile(pThis->hNmPipe, pThis->abBuf, 0 /*cbToRead*/, &cbRead, &pThis->Read.OverlappedIO))
     1420                    {
     1421                        rc = VINF_SUCCESS;
     1422                        if (iLoop > 10)
     1423                            RTThreadYield();
     1424                    }
     1425                    else if (GetLastError() == ERROR_IO_PENDING)
     1426                    {
     1427                        pThis->fZeroByteRead = true;
     1428                        hWait = pThis->Read.OverlappedIO.hEvent;
     1429                    }
    11861430                    else
    1187                         rc = RTErrConvertFromWin32(dwRc);
     1431                        rc = RTErrConvertFromWin32(GetLastError());
     1432                    if (RT_FAILURE(rc))
     1433                        break;
     1434                }
     1435
     1436                /*
     1437                 * Check for timeout.
     1438                 */
     1439                DWORD cMsMaxWait;
     1440                if (cMillies == RT_INDEFINITE_WAIT)
     1441                    cMsMaxWait = INFINITE;
     1442                else if (   hWait != INVALID_HANDLE_VALUE
     1443                         || iLoop > 10)
     1444                {
     1445                    uint64_t cMsElapsed = RTTimeMilliTS() - msStart;
     1446                    if (cMsElapsed <= cMillies)
     1447                        cMsMaxWait = cMillies - (uint32_t)cMsElapsed;
     1448                    else if (iLoop == 0)
     1449                        cMsMaxWait = cMillies ? 1 : 0;
     1450                    else
     1451                    {
     1452                        rc = VERR_TIMEOUT;
     1453                        break;
     1454                    }
     1455                }
     1456
     1457                /*
     1458                 * Wait and collect the result.
     1459                 */
     1460                if (hWait != INVALID_HANDLE_VALUE)
     1461                {
     1462                    RTCritSectLeave(&pThis->CritSect);
     1463
     1464                    DWORD rcWait = WaitForSingleObject(hWait, cMsMaxWait);
     1465
     1466                    int rc2 = RTCritSectEnter(&pThis->CritSect);
     1467                    AssertRC(rc2);
     1468
     1469                    rc = rtLocalIpcWinGetZeroReadResult(pThis, rcWait);
     1470                    break;
    11881471                }
    11891472            }
    11901473
    1191             if (RT_FAILURE(rc))
    1192                 break;
    1193         }
    1194     }
    1195 
    1196     int rc2 = RTCritSectLeave(&pThis->CritSect);
    1197     if (RT_SUCCESS(rc))
    1198         rc = rc2;
     1474            pThis->Read.hActiveThread = NIL_RTTHREAD;
     1475        }
     1476
     1477        rtLocalIpcSessionReleaseAndUnlock(pThis);
     1478    }
    11991479
    12001480    return rc;
     
    12151495    if (RT_SUCCESS(rc))
    12161496    {
    1217         ASMAtomicUoWriteBool(&pThis->fCancelled, true);
    1218         BOOL fRc = SetEvent(pThis->hEvent);
    1219         AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    1220 
    1221         RTCritSectLeave(&pThis->CritSect);
     1497        rtLocalIpcSessionRetain(pThis);
     1498        rc = rtLocalIpcWinCancel(pThis);
     1499        rtLocalIpcSessionReleaseAndUnlock(pThis);
    12221500    }
    12231501
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette