VirtualBox

Ignore:
Timestamp:
Sep 7, 2017 3:12:54 PM (8 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
117930
Message:

pdmifs.h,Serial: Reworked stream interface. The old design with the two read/write threads had a race where the read thread could access already destroyed VMM structures during destruction if data was read. This was solved by adding a poll callback which waits for data to arrive and which can be interrupt to make the thread respond to VM state changes and suspend before destruction starts. This required reworking all the drivers using it. DrvTCP was reworked to make use of the RTTcp*, RTSocket* and RTPoll* API in that process to get rid of platform dependent code there (which wasn't all available when the driver was createt).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Serial/DrvNamedPipe.cpp

    r62956 r68699  
    1 /* $Id$ */
     1  /* $Id$ */
    22/** @file
    33 * Named pipe / local socket stream driver.
     
    2626#include <iprt/stream.h>
    2727#include <iprt/alloc.h>
     28#include <iprt/pipe.h>
     29#include <iprt/poll.h>
    2830#include <iprt/string.h>
    2931#include <iprt/semaphore.h>
     32#include <iprt/socket.h>
    3033#include <iprt/uuid.h>
    3134
     
    4952*   Defined Constants And Macros                                                                                                 *
    5053*********************************************************************************************************************************/
    51 /** Converts a pointer to DRVNAMEDPIPE::IMedia to a PDRVNAMEDPIPE. */
    52 #define PDMISTREAM_2_DRVNAMEDPIPE(pInterface) ( (PDRVNAMEDPIPE)((uintptr_t)pInterface - RT_OFFSETOF(DRVNAMEDPIPE, IStream)) )
    53 
     54
     55#ifndef RT_OS_WINDOWS
     56# define DRVNAMEDPIPE_POLLSET_ID_SOCKET 0
     57# define DRVNAMEDPIPE_POLLSET_ID_WAKEUP 1
     58#endif
     59
     60# define DRVNAMEDPIPE_WAKEUP_REASON_EXTERNAL       0
     61# define DRVNAMEDPIPE_WAKEUP_REASON_NEW_CONNECTION 1
    5462
    5563/*********************************************************************************************************************************
     
    7482    /** File handle of the named pipe. */
    7583    HANDLE              NamedPipe;
     84    /** The wake event handle. */
     85    HANDLE              hEvtWake;
    7686    /** Overlapped structure for writes. */
    7787    OVERLAPPED          OverlappedWrite;
     
    8090    /** Listen thread wakeup semaphore */
    8191    RTSEMEVENTMULTI     ListenSem;
     92    /** Read buffer. */
     93    uint8_t             abBufRead[32];
     94    /** Write buffer. */
     95    uint8_t             abBufWrite[32];
     96    /** Read buffer currently used. */
     97    size_t              cbReadBufUsed;
     98    /** Size of the write buffer used. */
     99    size_t              cbWriteBufUsed;
     100    /** Flag whether a wake operation was caused by an external trigger. */
     101    volatile bool       fWakeExternal;
     102    /** Flag whether a read was started. */
     103    bool                fReadPending;
    82104#else /* !RT_OS_WINDOWS */
     105    /** Poll set used to wait for I/O events. */
     106    RTPOLLSET           hPollSet;
     107    /** Reading end of the wakeup pipe. */
     108    RTPIPE              hPipeWakeR;
     109    /** Writing end of the wakeup pipe. */
     110    RTPIPE              hPipeWakeW;
     111    /** Socket handle. */
     112    RTSOCKET            hSock;
     113    /** Flag whether the socket is in the pollset. */
     114    bool                fSockInPollSet;
    83115    /** Socket handle of the local socket for server. */
    84116    int                 LocalSocketServer;
    85     /** Socket handle of the local socket. */
    86     int                 LocalSocket;
    87117#endif /* !RT_OS_WINDOWS */
    88118    /** Thread for listening for new connections. */
     
    98128
    99129
     130/**
     131 * Kicks any possibly polling thread to get informed about changes.
     132 *
     133 * @returns VBOx status code.
     134 * @param   pThis                  The named pipe driver instance.
     135 * @param   bReason                The reason code to handle.
     136 */
     137static int drvNamedPipePollerKick(PDRVNAMEDPIPE pThis, uint8_t bReason)
     138{
     139#ifdef RT_OS_WINDOWS
     140    if (bReason == DRVNAMEDPIPE_WAKEUP_REASON_EXTERNAL)
     141        ASMAtomicXchgBool(&pThis->fWakeExternal, true);
     142    if (!SetEvent(pThis->hEvtWake))
     143        return RTErrConvertFromWin32(GetLastError());
     144
     145    return VINF_SUCCESS;
     146#else
     147    size_t cbWritten = 0;
     148    return RTPipeWrite(pThis->hPipeWakeW, &bReason, 1, &cbWritten);
     149#endif
     150}
     151
     152
     153/** @interface_method_impl{PDMISTREAM,pfnPoll} */
     154static DECLCALLBACK(int) drvNamedPipePoll(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies)
     155{
     156    int rc = VINF_SUCCESS;
     157    PDRVNAMEDPIPE pThis = RT_FROM_MEMBER(pInterface, DRVNAMEDPIPE, IStream);
     158
     159    LogFlowFunc(("pInterface=%#p fEvts=%#x pfEvts=%#p cMillies=%u\n", pInterface, fEvts, pfEvts, cMillies));
     160
     161#ifdef RT_OS_WINDOWS
     162    /* Immediately return if there is something to read or no write pending and the respective events are set. */
     163    *pfEvts = 0;
     164    if (   (fEvts & RTPOLL_EVT_READ)
     165        && pThis->cbReadBufUsed > 0)
     166        *pfEvts |= RTPOLL_EVT_READ;
     167    if (   (fEvts & RTPOLL_EVT_WRITE)
     168        && !pThis->cbWriteBufUsed)
     169        *pfEvts |= RTPOLL_EVT_WRITE;
     170
     171    if (*pfEvts)
     172        return VINF_SUCCESS;
     173
     174    while (RT_SUCCESS(rc))
     175    {
     176        /* Set up the waiting handles. */
     177        HANDLE ahEvts[3];
     178        unsigned cEvts = 0;
     179
     180        ahEvts[cEvts++] = pThis->hEvtWake;
     181        if (fEvts & RTPOLL_EVT_WRITE)
     182        {
     183            Assert(pThis->cbWriteBufUsed);
     184            ahEvts[cEvts++] = pThis->OverlappedWrite.hEvent;
     185        }
     186        if (   (fEvts & RTPOLL_EVT_READ)
     187            && pThis->NamedPipe != INVALID_HANDLE_VALUE
     188            && !pThis->fReadPending)
     189        {
     190            Assert(!pThis->cbReadBufUsed);
     191
     192            DWORD cbReallyRead;
     193            pThis->OverlappedRead.Offset     = 0;
     194            pThis->OverlappedRead.OffsetHigh = 0;
     195            if (!ReadFile(pThis->NamedPipe, &pThis->abBufRead[0], sizeof(pThis->abBufRead), &cbReallyRead, &pThis->OverlappedRead))
     196            {
     197                DWORD uError = GetLastError();
     198
     199                if (uError == ERROR_IO_PENDING)
     200                {
     201                    uError = 0;
     202                    pThis->fReadPending = true;
     203                }
     204
     205                if (   uError == ERROR_PIPE_LISTENING
     206                    || uError == ERROR_PIPE_NOT_CONNECTED)
     207                {
     208                    /* No connection yet/anymore */
     209                    cbReallyRead = 0;
     210                }
     211                else
     212                {
     213                    rc = RTErrConvertFromWin32(uError);
     214                    Log(("drvNamedPipePoll: ReadFile returned %d (%Rrc)\n", uError, rc));
     215                }
     216            }
     217            else
     218            {
     219                LogFlowFunc(("Read completed: cbReallyRead=%u\n", cbReallyRead));
     220                pThis->fReadPending = false;
     221                *pfEvts |= RTPOLL_EVT_READ;
     222                return VINF_SUCCESS;
     223            }
     224
     225            if (RT_FAILURE(rc))
     226            {
     227                Log(("drvNamedPipePoll: FileRead returned %Rrc fShutdown=%d\n", rc, pThis->fShutdown));
     228                if (    !pThis->fShutdown
     229                    &&  (   rc == VERR_EOF
     230                         || rc == VERR_BROKEN_PIPE
     231                        )
     232                   )
     233                {
     234                    FlushFileBuffers(pThis->NamedPipe);
     235                    DisconnectNamedPipe(pThis->NamedPipe);
     236                    if (!pThis->fIsServer)
     237                    {
     238                        CloseHandle(pThis->NamedPipe);
     239                        pThis->NamedPipe = INVALID_HANDLE_VALUE;
     240                    }
     241                    /* pretend success */
     242                    rc = VINF_SUCCESS;
     243                }
     244                cbReallyRead = 0;
     245            }
     246        }
     247
     248        if (pThis->fReadPending)
     249            ahEvts[cEvts++] = pThis->OverlappedRead.hEvent;
     250
     251        DWORD dwMillies = cMillies == RT_INDEFINITE_WAIT ? INFINITE : cMillies;
     252        DWORD uErr = WaitForMultipleObjects(cEvts, &ahEvts[0], FALSE /* bWaitAll */, dwMillies);
     253        if (uErr == WAIT_TIMEOUT)
     254            rc = VERR_TIMEOUT;
     255        else if (uErr == WAIT_FAILED)
     256            rc = RTErrConvertFromWin32(GetLastError());
     257        else
     258        {
     259            /* Something triggered. */
     260            unsigned idxEvt = uErr - WAIT_OBJECT_0;
     261            Assert(idxEvt < cEvts);
     262
     263            LogFlowFunc(("Interrupted by pipe activity: idxEvt=%u\n", idxEvt));
     264
     265            if (idxEvt == 0)
     266            {
     267                /* The wakeup triggered. */
     268                if (ASMAtomicXchgBool(&pThis->fWakeExternal, false))
     269                    rc = VERR_INTERRUPTED;
     270                else
     271                {
     272                    /*
     273                     * Internal event because there was a new connection from the listener thread,
     274                     * restart everything.
     275                     */
     276                    rc = VINF_SUCCESS;
     277                }
     278            }
     279            else if (ahEvts[idxEvt] == pThis->OverlappedWrite.hEvent)
     280            {
     281                LogFlowFunc(("Write completed\n"));
     282                /* Fetch the result of the write. */
     283                DWORD cbWritten = 0;
     284                if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedWrite, &cbWritten, TRUE) == FALSE)
     285                {
     286                    uErr = GetLastError();
     287                    rc = RTErrConvertFromWin32(uErr);
     288                    Log(("drvNamedPipePoll: Write completed with %d (%Rrc)\n", uErr, rc));
     289
     290                    if (RT_FAILURE(rc))
     291                    {
     292                        /** @todo WriteFile(pipe) has been observed to return  ERROR_NO_DATA
     293                         *        (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is
     294                         *        disconnected. */
     295                        if (    rc == VERR_EOF
     296                            ||  rc == VERR_BROKEN_PIPE)
     297                        {
     298                            FlushFileBuffers(pThis->NamedPipe);
     299                            DisconnectNamedPipe(pThis->NamedPipe);
     300                            if (!pThis->fIsServer)
     301                            {
     302                                CloseHandle(pThis->NamedPipe);
     303                                pThis->NamedPipe = INVALID_HANDLE_VALUE;
     304                            }
     305                            /* pretend success */
     306                            rc = VINF_SUCCESS;
     307                        }
     308                        cbWritten = (DWORD)pThis->cbWriteBufUsed;
     309                    }
     310                }
     311
     312                pThis->cbWriteBufUsed -= cbWritten;
     313                if (!pThis->cbWriteBufUsed && (fEvts & RTPOLL_EVT_WRITE))
     314                {
     315                    *pfEvts |= RTPOLL_EVT_WRITE;
     316                    break;
     317                }
     318            }
     319            else
     320            {
     321                Assert(ahEvts[idxEvt] == pThis->OverlappedRead.hEvent);
     322
     323                DWORD cbRead = 0;
     324                if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedRead, &cbRead, TRUE) == FALSE)
     325                {
     326                    uErr = GetLastError();
     327                    rc = RTErrConvertFromWin32(uErr);
     328                    Log(("drvNamedPipePoll: Read completed with %d (%Rrc)\n", uErr, rc));
     329
     330                    if (RT_FAILURE(rc))
     331                    {
     332                        /** @todo WriteFile(pipe) has been observed to return  ERROR_NO_DATA
     333                         *        (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is
     334                         *        disconnected. */
     335                        if (    rc == VERR_EOF
     336                            ||  rc == VERR_BROKEN_PIPE)
     337                        {
     338                            FlushFileBuffers(pThis->NamedPipe);
     339                            DisconnectNamedPipe(pThis->NamedPipe);
     340                            if (!pThis->fIsServer)
     341                            {
     342                                CloseHandle(pThis->NamedPipe);
     343                                pThis->NamedPipe = INVALID_HANDLE_VALUE;
     344                            }
     345                            /* pretend success */
     346                            rc = VINF_SUCCESS;
     347                        }
     348                        cbRead = 0;
     349                    }
     350                }
     351
     352                LogFlowFunc(("Read completed with cbRead=%u\n", cbRead));
     353                pThis->fReadPending = false;
     354                pThis->cbReadBufUsed = cbRead;
     355                if (pThis->cbReadBufUsed && (fEvts & RTPOLL_EVT_READ))
     356                {
     357                    *pfEvts |= RTPOLL_EVT_READ;
     358                    break;
     359                }
     360            }
     361        }
     362    }
     363#else
     364    if (pThis->hSock != NIL_RTSOCKET)
     365    {
     366        if (!pThis->fSockInPollSet)
     367        {
     368            rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hSock,
     369                                    fEvts, DRVNAMEDPIPE_POLLSET_ID_SOCKET);
     370            if (RT_SUCCESS(rc))
     371                pThis->fSockInPollSet = true;
     372        }
     373        else
     374        {
     375            /* Always include error event. */
     376            fEvts |= RTPOLL_EVT_ERROR;
     377            rc = RTPollSetEventsChange(pThis->hPollSet, DRVNAMEDPIPE_POLLSET_ID_SOCKET, fEvts);
     378            AssertRC(rc);
     379        }
     380    }
     381
     382    while (RT_SUCCESS(rc))
     383    {
     384        uint32_t fEvtsRecv = 0;
     385        uint32_t idHnd = 0;
     386
     387        rc = RTPoll(pThis->hPollSet, cMillies, &fEvtsRecv, &idHnd);
     388        if (RT_SUCCESS(rc))
     389        {
     390            if (idHnd == DRVNAMEDPIPE_POLLSET_ID_WAKEUP)
     391            {
     392                /* We got woken up, drain the pipe and return. */
     393                uint8_t bReason;
     394                size_t cbRead = 0;
     395                rc = RTPipeRead(pThis->hPipeWakeR, &bReason, 1, &cbRead);
     396                AssertRC(rc);
     397
     398                if (bReason == DRVNAMEDPIPE_WAKEUP_REASON_EXTERNAL)
     399                    rc = VERR_INTERRUPTED;
     400                else if (bReason == DRVNAMEDPIPE_WAKEUP_REASON_NEW_CONNECTION)
     401                {
     402                    Assert(!pThis->fSockInPollSet);
     403                    rc = RTPollSetAddSocket(pThis->hPollSet, pThis->hSock,
     404                                            fEvts, DRVNAMEDPIPE_POLLSET_ID_SOCKET);
     405                    if (RT_SUCCESS(rc))
     406                        pThis->fSockInPollSet = true;
     407                }
     408                else
     409                    AssertMsgFailed(("Unknown wakeup reason in pipe %u\n", bReason));
     410            }
     411            else
     412            {
     413                Assert(idHnd == DRVNAMEDPIPE_POLLSET_ID_SOCKET);
     414
     415                /* On error we close the socket here. */
     416                if (fEvtsRecv & RTPOLL_EVT_ERROR)
     417                {
     418                    rc = RTPollSetRemove(pThis->hPollSet, DRVNAMEDPIPE_POLLSET_ID_SOCKET);
     419                    AssertRC(rc);
     420
     421                    RTSocketClose(pThis->hSock);
     422                    pThis->hSock = NIL_RTSOCKET;
     423                    pThis->fSockInPollSet = false;
     424                    /* Continue with polling. */
     425                }
     426                else
     427                {
     428                    *pfEvts = fEvtsRecv;
     429                    break;
     430                }
     431            }
     432        }
     433    }
     434#endif
     435
     436    LogFlowFunc(("returns %Rrc\n", rc));
     437    return rc;
     438}
     439
     440
     441/** @interface_method_impl{PDMISTREAM,pfnPollInterrupt} */
     442static DECLCALLBACK(int) drvNamedPipePollInterrupt(PPDMISTREAM pInterface)
     443{
     444    PDRVNAMEDPIPE pThis = RT_FROM_MEMBER(pInterface, DRVNAMEDPIPE, IStream);
     445    return drvNamedPipePollerKick(pThis, DRVNAMEDPIPE_WAKEUP_REASON_EXTERNAL);
     446}
     447
     448
    100449/** @interface_method_impl{PDMISTREAM,pfnRead} */
    101450static DECLCALLBACK(int) drvNamedPipeRead(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)
    102451{
    103452    int rc = VINF_SUCCESS;
    104     PDRVNAMEDPIPE pThis = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);
     453    PDRVNAMEDPIPE pThis = RT_FROM_MEMBER(pInterface, DRVNAMEDPIPE, IStream);
    105454    LogFlow(("%s: pvBuf=%p *pcbRead=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbRead, pThis->pszLocation));
    106455
     
    109458    if (pThis->NamedPipe != INVALID_HANDLE_VALUE)
    110459    {
    111         DWORD cbReallyRead;
    112         pThis->OverlappedRead.Offset     = 0;
    113         pThis->OverlappedRead.OffsetHigh = 0;
    114         if (!ReadFile(pThis->NamedPipe, pvBuf, (DWORD)*pcbRead, &cbReallyRead, &pThis->OverlappedRead))
    115         {
    116             DWORD uError = GetLastError();
    117 
    118             if (uError == ERROR_IO_PENDING)
    119             {
    120                 uError = 0;
    121 
    122                 /* Wait for incoming bytes. */
    123                 if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedRead, &cbReallyRead, TRUE) == FALSE)
    124                     uError = GetLastError();
    125             }
    126 
    127             if (   uError == ERROR_PIPE_LISTENING
    128                 || uError == ERROR_PIPE_NOT_CONNECTED)
    129             {
    130                 /* No connection yet/anymore */
    131                 cbReallyRead = 0;
    132 
    133                 /* wait a bit or else we'll be called right back. */
    134                 RTThreadSleep(100);
    135             }
    136             else
    137             {
    138                 rc = RTErrConvertFromWin32(uError);
    139                 Log(("drvNamedPipeRead: ReadFile returned %d (%Rrc)\n", uError, rc));
    140             }
    141         }
    142 
    143         if (RT_FAILURE(rc))
    144         {
    145             Log(("drvNamedPipeRead: FileRead returned %Rrc fShutdown=%d\n", rc, pThis->fShutdown));
    146             if (    !pThis->fShutdown
    147                 &&  (   rc == VERR_EOF
    148                      || rc == VERR_BROKEN_PIPE
    149                     )
    150                )
    151             {
    152                 FlushFileBuffers(pThis->NamedPipe);
    153                 DisconnectNamedPipe(pThis->NamedPipe);
    154                 if (!pThis->fIsServer)
    155                 {
    156                     CloseHandle(pThis->NamedPipe);
    157                     pThis->NamedPipe = INVALID_HANDLE_VALUE;
    158                 }
    159                 /* pretend success */
     460        /* Check if there is something in the read buffer and return as much as we can. */
     461        if (pThis->cbReadBufUsed)
     462        {
     463            size_t cbRead = RT_MIN(*pcbRead, pThis->cbReadBufUsed);
     464
     465            memcpy(pvBuf, &pThis->abBufRead[0], cbRead);
     466            if (cbRead < pThis->cbReadBufUsed)
     467                memmove(&pThis->abBufRead[0], &pThis->abBufRead[cbRead], pThis->cbReadBufUsed - cbRead);
     468            pThis->cbReadBufUsed -= cbRead;
     469            *pcbRead = cbRead;
     470        }
     471        else
     472            *pcbRead = 0;
     473    }
     474#else /* !RT_OS_WINDOWS */
     475    if (pThis->hSock != NIL_RTSOCKET)
     476    {
     477        size_t cbRead;
     478        size_t cbBuf = *pcbRead;
     479        rc = RTSocketReadNB(pThis->hSock, pvBuf, cbBuf, &cbRead);
     480        if (RT_SUCCESS(rc))
     481        {
     482            if (!cbRead && rc != VINF_TRY_AGAIN)
     483            {
     484                rc = RTPollSetRemove(pThis->hPollSet, DRVNAMEDPIPE_POLLSET_ID_SOCKET);
     485                AssertRC(rc);
     486
     487                RTSocketClose(pThis->hSock);
     488                pThis->hSock = NIL_RTSOCKET;
     489                pThis->fSockInPollSet = false;
    160490                rc = VINF_SUCCESS;
    161491            }
    162             cbReallyRead = 0;
    163         }
    164         *pcbRead = (size_t)cbReallyRead;
    165     }
    166 #else /* !RT_OS_WINDOWS */
    167     if (pThis->LocalSocket != -1)
    168     {
    169         ssize_t cbReallyRead;
    170         cbReallyRead = recv(pThis->LocalSocket, pvBuf, *pcbRead, 0);
    171         if (cbReallyRead == 0)
    172         {
    173             int tmp = pThis->LocalSocket;
    174             pThis->LocalSocket = -1;
    175             close(tmp);
    176         }
    177         else if (cbReallyRead == -1)
    178         {
    179             cbReallyRead = 0;
    180             rc = RTErrConvertFromErrno(errno);
    181         }
    182         *pcbRead = cbReallyRead;
     492            *pcbRead = cbRead;
     493        }
    183494    }
    184495#endif /* !RT_OS_WINDOWS */
     
    198509{
    199510    int rc = VINF_SUCCESS;
    200     PDRVNAMEDPIPE pThis = PDMISTREAM_2_DRVNAMEDPIPE(pInterface);
     511    PDRVNAMEDPIPE pThis = RT_FROM_MEMBER(pInterface, DRVNAMEDPIPE, IStream);
    201512    LogFlow(("%s: pvBuf=%p *pcbWrite=%#x (%s)\n", __FUNCTION__, pvBuf, *pcbWrite, pThis->pszLocation));
    202513
     
    205516    if (pThis->NamedPipe != INVALID_HANDLE_VALUE)
    206517    {
    207         DWORD cbWritten = (DWORD)*pcbWrite;
    208         pThis->OverlappedWrite.Offset     = 0;
    209         pThis->OverlappedWrite.OffsetHigh = 0;
    210         if (!WriteFile(pThis->NamedPipe, pvBuf, cbWritten, NULL, &pThis->OverlappedWrite))
    211         {
    212             DWORD uError = GetLastError();
    213 
    214             if (   uError == ERROR_PIPE_LISTENING
    215                 || uError == ERROR_PIPE_NOT_CONNECTED)
    216             {
    217                 /* No connection yet/anymore; just discard the write (pretending everything was written). */;
    218             }
    219             else if (uError != ERROR_IO_PENDING)
    220             {
    221                 rc = RTErrConvertFromWin32(uError);
    222                 Log(("drvNamedPipeWrite: WriteFile returned %d (%Rrc)\n", uError, rc));
    223                 cbWritten = 0;
    224             }
    225             else
    226             {
    227                 /* Wait for the write to complete. */
    228                 if (GetOverlappedResult(pThis->NamedPipe, &pThis->OverlappedWrite, &cbWritten, TRUE /*bWait*/) == FALSE)
    229                     rc = RTErrConvertFromWin32(uError = GetLastError());
    230             }
    231         }
    232 
    233         if (RT_FAILURE(rc))
    234         {
    235             /** @todo WriteFile(pipe) has been observed to return  ERROR_NO_DATA
    236              *        (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is
    237              *        disconnected. */
    238             if (    rc == VERR_EOF
    239                 ||  rc == VERR_BROKEN_PIPE)
    240             {
    241                 FlushFileBuffers(pThis->NamedPipe);
    242                 DisconnectNamedPipe(pThis->NamedPipe);
    243                 if (!pThis->fIsServer)
    244                 {
    245                     CloseHandle(pThis->NamedPipe);
    246                     pThis->NamedPipe = INVALID_HANDLE_VALUE;
    247                 }
    248                 /* pretend success */
    249                 rc = VINF_SUCCESS;
    250             }
    251             cbWritten = 0;
    252         }
    253         *pcbWrite = cbWritten;
     518        /* Accept the data in case the write buffer is empty. */
     519        if (!pThis->cbWriteBufUsed)
     520        {
     521            size_t cbWrite = RT_MIN(*pcbWrite, sizeof(pThis->cbWriteBufUsed));
     522
     523            memcpy(&pThis->abBufWrite[0], pvBuf, cbWrite);
     524            pThis->cbWriteBufUsed += cbWrite;
     525
     526            /* Initiate the write. */
     527            pThis->OverlappedWrite.Offset     = 0;
     528            pThis->OverlappedWrite.OffsetHigh = 0;
     529            if (!WriteFile(pThis->NamedPipe, pvBuf, (DWORD)cbWrite, NULL, &pThis->OverlappedWrite))
     530            {
     531                DWORD uError = GetLastError();
     532
     533                if (   uError == ERROR_PIPE_LISTENING
     534                    || uError == ERROR_PIPE_NOT_CONNECTED)
     535                {
     536                    /* No connection yet/anymore; just discard the write (pretending everything was written). */
     537                     pThis->cbWriteBufUsed = 0;
     538                    cbWrite = *pcbWrite;
     539                }
     540                else if (uError != ERROR_IO_PENDING) /* We wait for the write to complete in the poll callback. */
     541                {
     542                    rc = RTErrConvertFromWin32(uError);
     543                    Log(("drvNamedPipeWrite: WriteFile returned %d (%Rrc)\n", uError, rc));
     544                    cbWrite = 0;
     545                }
     546            }
     547
     548            if (RT_FAILURE(rc))
     549            {
     550                /** @todo WriteFile(pipe) has been observed to return  ERROR_NO_DATA
     551                 *        (VERR_NO_DATA) instead of ERROR_BROKEN_PIPE, when the pipe is
     552                 *        disconnected. */
     553                if (    rc == VERR_EOF
     554                    ||  rc == VERR_BROKEN_PIPE)
     555                {
     556                    FlushFileBuffers(pThis->NamedPipe);
     557                    DisconnectNamedPipe(pThis->NamedPipe);
     558                    if (!pThis->fIsServer)
     559                    {
     560                        CloseHandle(pThis->NamedPipe);
     561                        pThis->NamedPipe = INVALID_HANDLE_VALUE;
     562                    }
     563                    /* pretend success */
     564                    rc = VINF_SUCCESS;
     565                }
     566                cbWrite = 0;
     567            }
     568
     569            *pcbWrite = cbWrite;
     570        }
     571        else
     572            *pcbWrite = 0;
    254573    }
    255574#else /* !RT_OS_WINDOWS */
    256     if (pThis->LocalSocket != -1)
    257     {
    258         ssize_t cbWritten;
    259         cbWritten = send(pThis->LocalSocket, pvBuf, *pcbWrite, 0);
    260         if (cbWritten == 0)
    261         {
    262             int tmp = pThis->LocalSocket;
    263             pThis->LocalSocket = -1;
    264             close(tmp);
    265         }
    266         else if (cbWritten == -1)
    267         {
    268             cbWritten = 0;
    269             rc = RTErrConvertFromErrno(errno);
    270         }
    271         *pcbWrite = cbWritten;
    272     }
     575    if (pThis->hSock != NIL_RTSOCKET)
     576    {
     577        size_t cbBuf = *pcbWrite;
     578        rc = RTSocketWriteNB(pThis->hSock, pvBuf, cbBuf, pcbWrite);
     579    }
     580    else
     581        *pcbWrite = 0;
    273582#endif /* !RT_OS_WINDOWS */
    274583
     
    331640                if (GetOverlappedResult(pThis->NamedPipe, &overlapped, &dummy, TRUE) == FALSE)
    332641                    hrc = GetLastError();
    333 
     642                else
     643                    drvNamedPipePollerKick(pThis, DRVNAMEDPIPE_WAKEUP_REASON_NEW_CONNECTION);
    334644            }
    335645
     
    362672            break;
    363673        }
    364         if (pThis->LocalSocket != -1)
     674        if (pThis->hSock != NIL_RTSOCKET)
    365675        {
    366676            LogRel(("NamedPipe%d: only single connection supported\n", pThis->pDrvIns->iInstance));
     
    368678        }
    369679        else
    370             pThis->LocalSocket = s;
    371 
     680        {
     681            RTSOCKET hSockNew = NIL_RTSOCKET;
     682            rc = RTSocketFromNative(&hSockNew, s);
     683            if (RT_SUCCESS(rc))
     684            {
     685                pThis->hSock = hSockNew;
     686                /* Inform the poller about the new socket. */
     687                drvNamedPipePollerKick(pThis, DRVNAMEDPIPE_WAKEUP_REASON_NEW_CONNECTION);
     688            }
     689            else
     690            {
     691                LogRel(("NamedPipe%d: Failed to wrap socket with %Rrc\n", pThis->pDrvIns->iInstance));
     692                close(s);
     693            }
     694        }
    372695#endif /* !RT_OS_WINDOWS */
    373696    }
     
    473796        pThis->OverlappedWrite.hEvent = NULL;
    474797    }
     798    if (pThis->hEvtWake != NULL)
     799    {
     800        CloseHandle(pThis->hEvtWake);
     801        pThis->hEvtWake = NULL;
     802    }
    475803#else /* !RT_OS_WINDOWS */
    476804    Assert(pThis->LocalSocketServer == -1);
    477     if (pThis->LocalSocket != -1)
    478     {
    479         int rc = shutdown(pThis->LocalSocket, SHUT_RDWR);
    480         AssertRC(rc == 0); NOREF(rc);
    481 
    482         rc = close(pThis->LocalSocket);
    483         Assert(rc == 0);
    484         pThis->LocalSocket = -1;
    485     }
     805
     806    if (pThis->hSock != NIL_RTSOCKET)
     807    {
     808        int rc = RTPollSetRemove(pThis->hPollSet, DRVNAMEDPIPE_POLLSET_ID_SOCKET);
     809        AssertRC(rc);
     810
     811        rc = RTSocketShutdown(pThis->hSock, true /* fRead */, true /* fWrite */);
     812        AssertRC(rc);
     813
     814        rc = RTSocketClose(pThis->hSock);
     815        AssertRC(rc); RT_NOREF(rc);
     816
     817        pThis->hSock = NIL_RTSOCKET;
     818    }
     819
     820    if (pThis->hPipeWakeR != NIL_RTPIPE)
     821    {
     822        int rc = RTPipeClose(pThis->hPipeWakeR);
     823        AssertRC(rc);
     824
     825        pThis->hPipeWakeR = NIL_RTPIPE;
     826    }
     827
     828    if (pThis->hPipeWakeW != NIL_RTPIPE)
     829    {
     830        int rc = RTPipeClose(pThis->hPipeWakeW);
     831        AssertRC(rc);
     832
     833        pThis->hPipeWakeW = NIL_RTPIPE;
     834    }
     835
     836    if (pThis->hPollSet != NIL_RTPOLLSET)
     837    {
     838        int rc = RTPollSetDestroy(pThis->hPollSet);
     839        AssertRC(rc);
     840
     841        pThis->hPollSet = NIL_RTPOLLSET;
     842    }
     843
    486844    if (   pThis->fIsServer
    487845        && pThis->pszLocation)
     
    539897    pThis->OverlappedWrite.hEvent       = NULL;
    540898    pThis->OverlappedRead.hEvent        = NULL;
     899    pThis->hEvtWake                     = NULL;
    541900#else /* !RT_OS_WINDOWS */
    542901    pThis->LocalSocketServer            = -1;
    543     pThis->LocalSocket                  = -1;
     902    pThis->hSock                        = NIL_RTSOCKET;
     903
     904    pThis->hPollSet                     = NIL_RTPOLLSET;
     905    pThis->hPipeWakeR                   = NIL_RTPIPE;
     906    pThis->hPipeWakeW                   = NIL_RTPIPE;
     907    pThis->fSockInPollSet               = false;
    544908#endif /* !RT_OS_WINDOWS */
    545909    pThis->ListenThread                 = NIL_RTTHREAD;
     
    548912    pDrvIns->IBase.pfnQueryInterface    = drvNamedPipeQueryInterface;
    549913    /* IStream */
     914    pThis->IStream.pfnPoll              = drvNamedPipePoll;
     915    pThis->IStream.pfnPollInterrupt     = drvNamedPipePollInterrupt;
    550916    pThis->IStream.pfnRead              = drvNamedPipeRead;
    551917    pThis->IStream.pfnWrite             = drvNamedPipeWrite;
     
    619985    AssertReturn(pThis->OverlappedRead.hEvent != NULL, VERR_OUT_OF_RESOURCES);
    620986
     987    pThis->hEvtWake = CreateEvent(NULL, FALSE, FALSE, NULL);
     988    AssertReturn(pThis->hEvtWake != NULL, VERR_OUT_OF_RESOURCES);
     989
    621990#else /* !RT_OS_WINDOWS */
     991    rc = RTPipeCreate(&pThis->hPipeWakeR, &pThis->hPipeWakeW, 0 /* fFlags */);
     992    if (RT_FAILURE(rc))
     993        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
     994                                   N_("DrvTCP#%d: Failed to create wake pipe"), pDrvIns->iInstance);
     995
     996    rc = RTPollSetCreate(&pThis->hPollSet);
     997    if (RT_FAILURE(rc))
     998        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
     999                                   N_("DrvTCP#%d: Failed to create poll set"), pDrvIns->iInstance);
     1000
     1001    rc = RTPollSetAddPipe(pThis->hPollSet, pThis->hPipeWakeR,
     1002                            RTPOLL_EVT_READ | RTPOLL_EVT_ERROR,
     1003                            DRVNAMEDPIPE_POLLSET_ID_WAKEUP);
     1004    if (RT_FAILURE(rc))
     1005        return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
     1006                                   N_("DrvTCP#%d failed to add wakeup pipe for %s to poll set"),
     1007                                   pDrvIns->iInstance, pThis->pszLocation);
     1008
    6221009    int s = socket(PF_UNIX, SOCK_STREAM, 0);
    6231010    if (s == -1)
     
    6481035    {
    6491036        /* Connect to the local socket. */
    650         pThis->LocalSocket = s;
    6511037        if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1)
    6521038            return PDMDrvHlpVMSetError(pDrvIns, RTErrConvertFromErrno(errno), RT_SRC_POS,
    6531039                                       N_("NamedPipe#%d failed to connect to local socket %s"),
    6541040                                       pDrvIns->iInstance, pThis->pszLocation);
     1041
     1042        rc = RTSocketFromNative(&pThis->hSock, s);
     1043        if (RT_FAILURE(rc))
     1044        {
     1045            close(s);
     1046            return PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS,
     1047                                       N_("NamedPipe#%d failed to wrap socket %Rrc"),
     1048                                       pDrvIns->iInstance, pThis->pszLocation);
     1049        }
    6551050    }
    6561051#endif /* !RT_OS_WINDOWS */
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