VirtualBox

Changeset 47051 in vbox for trunk


Ignore:
Timestamp:
Jul 9, 2013 12:15:44 PM (12 years ago)
Author:
vboxsync
Message:

IPRT/localipc-win.cpp: Update on implementation (untested so far), also now should deal with NT4 + SDDL creation more dynamically.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/localipc.h

    r47009 r47051  
    44
    55/*
    6  * Copyright (C) 2006-2010 Oracle Corporation
     6 * Copyright (C) 2006-2013 Oracle Corporation
    77 *
    88 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    7676/** @name RTLocalIpcServerCreate flags
    7777 * @{ */
    78 /** The server can handle multiple session. */
     78/** The server can handle multiple sessions. */
    7979#define RTLOCALIPC_FLAGS_MULTI_SESSION      RT_BIT_32(0)
    8080/** The mask of valid flags. */
     
    151151 * @param   pvBuffer            Where to store the data.
    152152 * @param   cbBuffer            If pcbRead is non-NULL this indicates the maximum number of
    153  *                              bytes to read. If pcbRead is NULL the this is the exact number
     153 *                              bytes to read. If pcbRead is NULL then this is the exact number
    154154 *                              of bytes to read.
    155155 * @param   pcbRead             Optional argument for indicating a partial read and returning
  • trunk/src/VBox/Runtime/r3/win/localipc-win.cpp

    r44529 r47051  
    55
    66/*
    7  * Copyright (C) 2008-2010 Oracle Corporation
     7 * Copyright (C) 2008-2013 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4242#include <sddl.h>
    4343
     44#include <iprt/alloc.h>
     45#include <iprt/asm.h>
     46#include <iprt/assert.h>
     47#include <iprt/critsect.h>
     48#include <iprt/err.h>
     49#include <iprt/ldr.h>
    4450#include <iprt/localipc.h>
     51#include <iprt/param.h>
     52#include <iprt/string.h>
    4553#include <iprt/thread.h>
    46 #include <iprt/critsect.h>
    47 #include <iprt/alloc.h>
    48 #include <iprt/assert.h>
    49 #include <iprt/param.h>
    50 #include <iprt/err.h>
    51 #include <iprt/string.h>
    52 #include <iprt/asm.h>
    5354
    5455#include "internal/magics.h"
     
    139140{
    140141    /** The magic (RTLOCALIPCSESSION_MAGIC). */
    141     uint32_t u32Magic;
     142    uint32_t            u32Magic;
    142143    /** Critical section protecting the structure. */
    143     RTCRITSECT CritSect;
     144    RTCRITSECT          CritSect;
    144145    /** The number of references to the instance.
    145146     * @remarks The reference counting isn't race proof. */
    146     uint32_t volatile cRefs;
     147    uint32_t volatile   cRefs;
     148    /** Set if there is already pending I/O. */
     149    bool                fIOPending;
    147150    /** Indicates that there is a pending cancel request. */
    148     bool volatile fCancelled;
     151    bool volatile       fCancelled;
    149152    /** The name pipe handle. */
    150     HANDLE hNmPipe;
     153    HANDLE              hNmPipe;
    151154    /** The handle to the event object we're using for overlapped I/O. */
    152     HANDLE hEvent;
     155    HANDLE              hEvent;
    153156    /** The overlapped I/O structure. */
    154     OVERLAPPED OverlappedIO;
     157    OVERLAPPED          OverlappedIO;
     158    /** Bounce buffer for writes. */
     159    uint8_t            *pbBounceBuf;
     160    /** Amount of used buffer space. */
     161    size_t              cbBounceBufUsed;
     162    /** Amount of allocated buffer space. */
     163    size_t              cbBounceBufAlloc;
    155164} RTLOCALIPCSESSIONINT;
    156165/** Pointer to a local IPC session instance (Windows). */
    157166typedef RTLOCALIPCSESSIONINT *PRTLOCALIPCSESSIONINT;
     167
     168typedef BOOL WINAPI FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR(LPCTSTR, DWORD, PSECURITY_DESCRIPTOR, PULONG);
     169typedef FNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR
     170    *PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR; /* No, nobody fell on the keyboard, really! */
    158171
    159172
     
    169182 * This is used by both RTLocalIpcServerCreate and RTLocalIpcServerListen.
    170183 *
    171  * @returns Windows error code, that is NO_ERROR and *phNmPipe on success and some ERROR_* on failure.
    172  *
     184 * @return  IPRT status code.
    173185 * @param   phNmPipe            Where to store the named pipe handle on success. This
    174186 *                              will be set to INVALID_HANDLE_VALUE on failure.
     
    177189 *                              Governs the FILE_FLAG_FIRST_PIPE_INSTANCE flag.
    178190 */
    179 static DWORD rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst)
     191static int rtLocalIpcServerWinCreatePipeInstance(PHANDLE phNmPipe, const char *pszFullPipeName, bool fFirst)
    180192{
    181193    *phNmPipe = INVALID_HANDLE_VALUE;
    182194
    183     /*
    184      * We'll create a security descriptor from a SDDL that denies
    185      * access to network clients (this is local IPC after all), it
    186      * makes some further restrictions to prevent non-authenticated
    187      * users from screwing around.
    188      */
    189     DWORD err;
     195    /** @todo Stuff this into RTInitOnce. Later. */
     196    PFNCONVERTSTRINGSECURITYDESCRIPTORTOSECURITYDESCRIPTOR
     197        pfnConvertStringSecurityDescriptorToSecurityDescriptor = NULL;
     198
     199    RTLDRMOD hAdvApi32 = NIL_RTLDRMOD;
     200    int rc = RTLdrLoadSystem("Advapi32.lib", true /*fNoUnload*/, &hAdvApi32);
     201    if (RT_SUCCESS(rc))
     202        rc = RTLdrGetSymbol(hAdvApi32, "ConvertStringSecurityDescriptorToSecurityDescriptor",
     203                            (void**)&pfnConvertStringSecurityDescriptorToSecurityDescriptor);
     204
    190205    PSECURITY_DESCRIPTOR pSecDesc = NULL;
    191 #if 0 /** @todo dynamically resolve this as it is the only thing that prevents
    192        * loading IPRT on NT4. */
    193     if (ConvertStringSecurityDescriptorToSecurityDescriptor(RTLOCALIPC_WIN_SDDL,
    194                                                             SDDL_REVISION_1,
    195                                                             &pSecDesc,
    196                                                             NULL))
    197 #else
    198     AssertFatalFailed();
    199     SetLastError(-1);
    200     if (0)
    201 #endif
     206    if (RT_SUCCESS(rc))
     207    {
     208        AssertPtr(pfnConvertStringSecurityDescriptorToSecurityDescriptor);
     209
     210        /*
     211         * We'll create a security descriptor from a SDDL that denies
     212         * access to network clients (this is local IPC after all), it
     213         * makes some further restrictions to prevent non-authenticated
     214         * users from screwing around.
     215         */
     216        if (!pfnConvertStringSecurityDescriptorToSecurityDescriptor(RTLOCALIPC_WIN_SDDL,
     217                                                                    SDDL_REVISION_1,
     218                                                                    &pSecDesc,
     219                                                                    NULL))
     220        {
     221            rc = RTErrConvertFromWin32(GetLastError());
     222        }
     223    }
     224    else
     225    {
     226        /* Windows OSes < W2K SP2 not supported for now, bail out. */
     227        /** @todo Implement me! */
     228        rc = VERR_NOT_SUPPORTED;
     229    }
     230
     231    if (hAdvApi32 != NIL_RTLDRMOD)
     232         RTLdrClose(hAdvApi32);
     233
     234    if (RT_SUCCESS(rc))
    202235    {
    203236        SECURITY_ATTRIBUTES SecAttrs;
     
    209242                        | PIPE_WAIT
    210243                        | FILE_FLAG_OVERLAPPED;
    211         if (fFirst)
    212             fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE; /* Note! Requires W2K SP2+. */
     244
     245        bool fSupportsFirstInstance = false;
     246
     247        OSVERSIONINFOEX OSInfoEx;
     248        RT_ZERO(OSInfoEx);
     249        OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
     250        if (   GetVersionEx((LPOSVERSIONINFO) &OSInfoEx)
     251            && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT)
     252        {
     253            if (   /* Vista+. */
     254                   OSInfoEx.dwMajorVersion >= 6
     255                   /* Windows XP+. */
     256                || (   OSInfoEx.dwMajorVersion == 5
     257                    && OSInfoEx.dwMinorVersion >  0)
     258                   /* Windows 2000. */
     259                || (   OSInfoEx.dwMajorVersion == 5
     260                    && OSInfoEx.dwMinorVersion == 0
     261                    && OSInfoEx.wServicePackMajor >= 2))
     262            {
     263                /* Requires at least W2K (5.0) SP2+. This is non-fatal. */
     264                fSupportsFirstInstance = true;
     265            }
     266        }
     267
     268        if (fFirst && fSupportsFirstInstance)
     269            fOpenMode |= FILE_FLAG_FIRST_PIPE_INSTANCE;
    213270
    214271        HANDLE hNmPipe = CreateNamedPipe(pszFullPipeName,               /* lpName */
     
    220277                                         30*1000,                       /* nDefaultTimeOut = 30 sec */
    221278                                         &SecAttrs);                    /* lpSecurityAttributes */
    222         err = GetLastError();
     279
    223280        LocalFree(pSecDesc);
    224281        if (hNmPipe != INVALID_HANDLE_VALUE)
    225282        {
    226283            *phNmPipe = hNmPipe;
    227             return NO_ERROR;
    228         }
    229     }
    230     else
    231         err = GetLastError();
    232 
    233     AssertReturn(err != NO_ERROR, ERROR_GEN_FAILURE);
    234     return err;
     284        }
     285        else
     286            rc = RTErrConvertFromWin32(GetLastError());
     287    }
     288
     289    return rc;
    235290}
    236291
     
    264319    if (RT_SUCCESS(rc))
    265320    {
    266         DWORD err = NO_ERROR;
    267         pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL /*lpName*/);
     321        pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
     322                                    FALSE /*bInitialState*/, NULL /*lpName*/);
    268323        if (pThis->hEvent != NULL)
    269324        {
    270             memset(&pThis->OverlappedIO, 0, sizeof(pThis->OverlappedIO));
     325            RT_ZERO(pThis->OverlappedIO);
    271326            pThis->OverlappedIO.Internal = STATUS_PENDING;
    272327            pThis->OverlappedIO.hEvent = pThis->hEvent;
    273328
    274             err = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe, pThis->szName, true /* fFirst */);
    275             if (err == NO_ERROR)
     329            rc = rtLocalIpcServerWinCreatePipeInstance(&pThis->hNmPipe,
     330                                                       pThis->szName, true /* fFirst */);
     331            if (RT_SUCCESS(rc))
    276332            {
    277333                *phServer = pThis;
    278334                return VINF_SUCCESS;
    279335            }
     336
     337            BOOL fRc = CloseHandle(pThis->hEvent);
     338            AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
    280339        }
    281340        else
    282             err = GetLastError();
    283         rc = RTErrConvertFromWin32(err);
     341            rc = RTErrConvertFromWin32(GetLastError());
     342
     343        int rc2 = RTCritSectDelete(&pThis->CritSect);
     344        AssertRC(rc2);
    284345    }
    285346    RTMemFree(pThis);
     
    372433        /*
    373434         * Try connect a client. We need to use overlapped I/O here because
    374          * of the cancellation a by RTLocalIpcServerCancel and RTLocalIpcServerDestroy.
     435         * of the cancellation done by RTLocalIpcServerCancel and RTLocalIpcServerDestroy.
    375436         */
    376437        SetLastError(NO_ERROR);
     
    387448
    388449        RTCritSectEnter(&pThis->CritSect);
    389         if (    !pThis->fCancelled
     450        if (    !pThis->fCancelled /* Event signalled but not cancelled? */
    390451            &&  pThis->u32Magic == RTLOCALIPCSERVER_MAGIC)
    391452        {
     
    397458             * will be assigned to the client session.
    398459             */
    399             if (    fRc
    400                 ||  err == ERROR_PIPE_CONNECTED)
     460            if (   fRc
     461                || err == ERROR_PIPE_CONNECTED)
    401462            {
    402463                HANDLE hNmPipe;
     
    488549static int rtLocalIpcWinCreateSession(PRTLOCALIPCSESSION phClientSession, HANDLE hNmPipeSession)
    489550{
     551    AssertPtrReturn(phClientSession, VERR_INVALID_POINTER);
     552    AssertReturn(hNmPipeSession != INVALID_HANDLE_VALUE, VERR_INVALID_PARAMETER);
     553
    490554    int rc;
    491555
     
    504568        if (RT_SUCCESS(rc))
    505569        {
    506             pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/, FALSE /*bInitialState*/, NULL /*lpName*/);
     570            pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
     571                                        FALSE /*bInitialState*/, NULL /*lpName*/);
    507572            if (pThis->hEvent != NULL)
    508573            {
    509                 memset(&pThis->OverlappedIO, 0, sizeof(pThis->OverlappedIO));
     574                RT_ZERO(pThis->OverlappedIO);
    510575                pThis->OverlappedIO.Internal = STATUS_PENDING;
    511576                pThis->OverlappedIO.hEvent = pThis->hEvent;
     
    529594}
    530595
    531 
    532596RTDECL(int) RTLocalIpcSessionConnect(PRTLOCALIPCSESSION phSession, const char *pszName, uint32_t fFlags)
    533597{
    534     return VINF_SUCCESS;
     598    AssertPtrReturn(phSession, VERR_INVALID_POINTER);
     599    AssertPtrReturn(pszName, VERR_INVALID_POINTER);
     600    AssertReturn(!fFlags, VERR_INVALID_PARAMETER); /* Flags currently unused, must be 0. */
     601
     602    PRTLOCALIPCSESSIONINT pThis = (PRTLOCALIPCSESSIONINT)RTMemAlloc(sizeof(*pThis));
     603    if (!pThis)
     604        return VERR_NO_MEMORY;
     605
     606    pThis->u32Magic = RTLOCALIPCSESSION_MAGIC;
     607    pThis->cRefs = 1; /* The one we return. */
     608    pThis->fIOPending = false;
     609    pThis->fCancelled = false;
     610    pThis->pbBounceBuf = NULL;
     611    pThis->cbBounceBufAlloc = 0;
     612    pThis->cbBounceBufUsed = 0;
     613
     614    int rc = RTCritSectInit(&pThis->CritSect);
     615    if (RT_SUCCESS(rc))
     616    {
     617        pThis->hEvent = CreateEvent(NULL /*lpEventAttributes*/, TRUE /*bManualReset*/,
     618                                    FALSE /*bInitialState*/, NULL /*lpName*/);
     619        if (pThis->hEvent != NULL)
     620        {
     621            RT_ZERO(pThis->OverlappedIO);
     622            pThis->OverlappedIO.Internal = STATUS_PENDING;
     623            pThis->OverlappedIO.hEvent = pThis->hEvent;
     624
     625            char *pszPipe;
     626            if (RTStrAPrintf(&pszPipe, "%s%s", RTLOCALIPC_WIN_PREFIX, pszName))
     627            {
     628                HANDLE hPipe = CreateFile(pszPipe,                  /* pipe name */
     629                                          GENERIC_READ |            /* read and write access */
     630                                          GENERIC_WRITE,
     631                                          0,                        /* no sharing */
     632                                          NULL,                     /* default security attributes */
     633                                          OPEN_EXISTING,            /* opens existing pipe */
     634                                          FILE_FLAG_OVERLAPPED,     /* default attributes */
     635                                          NULL);                    /* no template file */
     636                RTStrFree(pszPipe);
     637                if (hPipe != INVALID_HANDLE_VALUE)
     638                {
     639                    pThis->hNmPipe = hPipe;
     640                    return VINF_SUCCESS;
     641                }
     642                else
     643                    rc = RTErrConvertFromWin32(GetLastError());
     644            }
     645            else
     646                rc = VERR_NO_MEMORY;
     647
     648            BOOL fRc = CloseHandle(pThis->hEvent);
     649            AssertMsg(fRc, ("%d\n", GetLastError())); NOREF(fRc);
     650        }
     651        else
     652            rc = RTErrConvertFromWin32(GetLastError());
     653
     654        int rc2 = RTCritSectDelete(&pThis->CritSect);
     655        AssertRC(rc2);
     656    }
     657
     658    RTMemFree(pThis);
     659    return rc;
    535660}
    536661
     
    594719RTDECL(int) RTLocalIpcSessionRead(RTLOCALIPCSESSION hSession, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
    595720{
     721    PRTLOCALIPCSESSIONINT pThis = hSession;
     722    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     723    AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
     724    AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
     725    /* pcbRead is optional. */
     726
     727    int rc = RTCritSectEnter(&pThis->CritSect);
     728    if (RT_SUCCESS(rc))
     729    {
     730        /* No concurrent readers, sorry. */
     731        if (pThis->cRefs == 0)
     732        {
     733            pThis->cRefs++;
     734
     735            /*
     736             * If pcbRead is non-NULL this indicates the maximum number of bytes to read.
     737             * If pcbRead is NULL the this is the exact number of bytes to read.
     738             */
     739            size_t cbToRead = pcbRead ? *pcbRead : cbBuffer;
     740            size_t cbTotalRead = 0;
     741            while (cbToRead > 0)
     742            {
     743                /*
     744                 * Kick of a an overlapped read.  It should return immediately if
     745                 * there is bytes in the buffer.  If not, we'll cancel it and see
     746                 * what we get back.
     747                 */
     748                rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
     749                DWORD cbRead = 0;
     750                pThis->fIOPending = true;
     751                RTCritSectLeave(&pThis->CritSect);
     752
     753                if (ReadFile(pThis->hNmPipe, pvBuffer,
     754                             cbToRead <= ~(DWORD)0 ? (DWORD)cbToRead : ~(DWORD)0,
     755                             &cbRead, &pThis->OverlappedIO))
     756                    rc = VINF_SUCCESS;
     757                else if (GetLastError() == ERROR_IO_PENDING)
     758                {
     759                    WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
     760                    if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO,
     761                                            &cbRead, TRUE /*fWait*/))
     762                        rc = VINF_SUCCESS;
     763                    else
     764                        rc = RTErrConvertFromWin32(GetLastError());
     765                }
     766                else
     767                    rc = RTErrConvertFromWin32(GetLastError());
     768
     769                RTCritSectEnter(&pThis->CritSect);
     770                pThis->fIOPending = false;
     771                if (RT_FAILURE(rc))
     772                    break;
     773
     774                /* Advance. */
     775                cbToRead    -= cbRead;
     776                cbTotalRead += cbRead;
     777                pvBuffer     = (uint8_t *)pvBuffer + cbRead;
     778            }
     779
     780            if (pcbRead)
     781            {
     782                *pcbRead = cbTotalRead;
     783                if (   RT_FAILURE(rc)
     784                    && cbTotalRead
     785                    && rc != VERR_INVALID_POINTER)
     786                    rc = VINF_SUCCESS;
     787            }
     788
     789            pThis->cRefs--;
     790        }
     791        else
     792            rc = VERR_WRONG_ORDER;
     793        RTCritSectLeave(&pThis->CritSect);
     794    }
     795
     796    return rc;
     797}
     798
     799
     800/**
     801 * Common worker for handling I/O completion.
     802 *
     803 * This is used by RTLocalIpcSessionClose and RTLocalIpcSessionWrite.
     804 *
     805 * @returns IPRT status code.
     806 * @param   pThis               The pipe instance handle.
     807 */
     808static int rtLocalIpcSessionWriteCheckCompletion(PRTLOCALIPCSESSIONINT pThis)
     809{
     810    int rc;
     811    DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, 0);
     812    if (dwRc == WAIT_OBJECT_0)
     813    {
     814        DWORD cbWritten = 0;
     815        if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE))
     816        {
     817            for (;;)
     818            {
     819                if (cbWritten >= pThis->cbBounceBufUsed)
     820                {
     821                    pThis->fIOPending = false;
     822                    rc = VINF_SUCCESS;
     823                    break;
     824                }
     825
     826                /* resubmit the remainder of the buffer - can this actually happen? */
     827                memmove(&pThis->pbBounceBuf[0], &pThis->pbBounceBuf[cbWritten], pThis->cbBounceBufUsed - cbWritten);
     828                rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
     829                if (!WriteFile(pThis->hNmPipe, pThis->pbBounceBuf, (DWORD)pThis->cbBounceBufUsed,
     830                               &cbWritten, &pThis->OverlappedIO))
     831                {
     832                    if (GetLastError() == ERROR_IO_PENDING)
     833                        rc = VINF_TRY_AGAIN;
     834                    else
     835                    {
     836                        pThis->fIOPending = false;
     837                        if (GetLastError() == ERROR_NO_DATA)
     838                            rc = VERR_BROKEN_PIPE;
     839                        else
     840                            rc = RTErrConvertFromWin32(GetLastError());
     841                    }
     842                    break;
     843                }
     844                Assert(cbWritten > 0);
     845            }
     846        }
     847        else
     848        {
     849            pThis->fIOPending = false;
     850            rc = RTErrConvertFromWin32(GetLastError());
     851        }
     852    }
     853    else if (dwRc == WAIT_TIMEOUT)
     854        rc = VINF_TRY_AGAIN;
     855    else
     856    {
     857        pThis->fIOPending = false;
     858        if (dwRc == WAIT_ABANDONED)
     859            rc = VERR_INVALID_HANDLE;
     860        else
     861            rc = RTErrConvertFromWin32(GetLastError());
     862    }
     863    return rc;
     864}
     865
     866
     867RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuffer, size_t cbBuffer)
     868{
     869    PRTLOCALIPCSESSIONINT pThis = hSession;
     870    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     871    AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
     872    AssertPtrReturn(pvBuffer, VERR_INVALID_POINTER);
     873    AssertReturn(cbBuffer, VERR_INVALID_PARAMETER);
     874
     875    int rc = RTCritSectEnter(&pThis->CritSect);
     876    if (RT_SUCCESS(rc))
     877    {
     878        /* No concurrent writers, sorry. */
     879        if (pThis->cRefs == 0)
     880        {
     881            pThis->cRefs++;
     882
     883            /*
     884             * If I/O is pending, wait for it to complete.
     885             */
     886            if (pThis->fIOPending)
     887            {
     888                rc = rtLocalIpcSessionWriteCheckCompletion(pThis);
     889                while (rc == VINF_TRY_AGAIN)
     890                {
     891                    Assert(pThis->fIOPending);
     892                    HANDLE hEvent = pThis->OverlappedIO.hEvent;
     893                    RTCritSectLeave(&pThis->CritSect);
     894                    WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
     895                    RTCritSectEnter(&pThis->CritSect);
     896                }
     897            }
     898            if (RT_SUCCESS(rc))
     899            {
     900                Assert(!pThis->fIOPending);
     901
     902                /*
     903                 * Try write everything.
     904                 * No bounce buffering, cUsers protects us.
     905                 */
     906                size_t cbTotalWritten = 0;
     907                while (cbBuffer > 0)
     908                {
     909                    rc = ResetEvent(pThis->OverlappedIO.hEvent); Assert(rc == TRUE);
     910                    pThis->fIOPending = true;
     911                    RTCritSectLeave(&pThis->CritSect);
     912
     913                    DWORD cbWritten = 0;
     914                    if (WriteFile(pThis->hNmPipe, pvBuffer,
     915                                  cbBuffer <= ~(DWORD)0 ? (DWORD)cbBuffer : ~(DWORD)0,
     916                                  &cbWritten, &pThis->OverlappedIO))
     917                        rc = VINF_SUCCESS;
     918                    else if (GetLastError() == ERROR_IO_PENDING)
     919                    {
     920                        WaitForSingleObject(pThis->OverlappedIO.hEvent, INFINITE);
     921                        if (GetOverlappedResult(pThis->hNmPipe, &pThis->OverlappedIO, &cbWritten, TRUE /*fWait*/))
     922                            rc = VINF_SUCCESS;
     923                        else
     924                            rc = RTErrConvertFromWin32(GetLastError());
     925                    }
     926                    else if (GetLastError() == ERROR_NO_DATA)
     927                        rc = VERR_BROKEN_PIPE;
     928                    else
     929                        rc = RTErrConvertFromWin32(GetLastError());
     930
     931                    RTCritSectEnter(&pThis->CritSect);
     932                    pThis->fIOPending = false;
     933                    if (RT_FAILURE(rc))
     934                        break;
     935
     936                    /* Advance. */
     937                    pvBuffer        = (char const *)pvBuffer + cbWritten;
     938                    cbTotalWritten += cbWritten;
     939                    cbBuffer       -= cbWritten;
     940                }
     941            }
     942
     943            pThis->cRefs--;
     944        }
     945        else
     946            rc = VERR_WRONG_ORDER;
     947        RTCritSectLeave(&pThis->CritSect);
     948    }
     949
     950    return rc;
     951}
     952
     953
     954RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
     955{
     956    /* No flushing on Windows needed since RTLocalIpcSessionWrite will block until
     957     * all data was written (or an error occurred). */
     958    /** @todo Implement this as soon as we want an explicit asynchronous version of
     959     *        RTLocalIpcSessionWrite on Windows. */
    596960    return VINF_SUCCESS;
    597961}
    598962
    599963
    600 RTDECL(int) RTLocalIpcSessionWrite(RTLOCALIPCSESSION hSession, const void *pvBuffer, size_t cbBuffer)
     964RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
     965{
     966    PRTLOCALIPCSESSIONINT pThis = hSession;
     967    AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     968    AssertReturn(pThis->u32Magic == RTLOCALIPCSESSION_MAGIC, VERR_INVALID_HANDLE);
     969
     970    int rc = RTCritSectEnter(&pThis->CritSect);
     971    if (RT_SUCCESS(rc))
     972    {
     973        /* No concurrent waiters, sorry. */
     974        if (pThis->cRefs == 0)
     975        {
     976            pThis->cRefs++;
     977            RTCritSectLeave(&pThis->CritSect);
     978
     979            DWORD dwTimeout = cMillies == RT_INDEFINITE_WAIT
     980                            ? INFINITE : cMillies;
     981            DWORD dwRc = WaitForSingleObject(pThis->OverlappedIO.hEvent, dwTimeout);
     982
     983            RTCritSectEnter(&pThis->CritSect);
     984            if (dwRc == WAIT_TIMEOUT)
     985            {
     986                rc = VERR_TIMEOUT;
     987            }
     988            else if (dwRc == WAIT_ABANDONED)
     989            {
     990                rc = VERR_BROKEN_PIPE;
     991            }
     992            else if (dwRc == WAIT_FAILED)
     993                rc = RTErrConvertFromWin32(GetLastError());
     994
     995            pThis->cRefs--;
     996        }
     997        else
     998            rc = VERR_WRONG_ORDER;
     999        RTCritSectLeave(&pThis->CritSect);
     1000    }
     1001
     1002    return rc;
     1003}
     1004
     1005
     1006RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
    6011007{
    6021008    return VINF_SUCCESS;
     
    6041010
    6051011
    606 RTDECL(int) RTLocalIpcSessionFlush(RTLOCALIPCSESSION hSession)
    607 {
    608     return VINF_SUCCESS;
    609 }
    610 
    611 
    612 RTDECL(int) RTLocalIpcSessionWaitForData(RTLOCALIPCSESSION hSession, uint32_t cMillies)
    613 {
    614     RTThreadSleep(1000);
    615     return VINF_SUCCESS;
    616 }
    617 
    618 
    619 RTDECL(int) RTLocalIpcSessionCancel(RTLOCALIPCSESSION hSession)
    620 {
    621     return VINF_SUCCESS;
    622 }
    623 
    624 
    6251012RTDECL(int) RTLocalIpcSessionQueryProcess(RTLOCALIPCSESSION hSession, PRTPROCESS pProcess)
    6261013{
Note: See TracChangeset for help on using the changeset viewer.

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