VirtualBox

Changeset 31098 in vbox


Ignore:
Timestamp:
Jul 26, 2010 9:06:52 AM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
64050
Message:

iSCSI: First part for async I/O. Move I/O into a separate thread and handle NOP-in requests properly to prevent disconnects if the guest isn't doing any I/O.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/VBoxHDD.h

    r30863 r31098  
    10051005}
    10061006
     1007/** Forward declaration of a VD socket. */
     1008typedef struct VDSOCKETINT *VDSOCKET;
     1009/** Pointer to a VD socket. */
     1010typedef VDSOCKET *PVDSOCKET;
     1011/** Nil socket handle. */
     1012#define NIL_VDSOCKET ((VDSOCKET)0)
     1013
     1014/** Connect flag to indicate that the backend wants to use the extended
     1015 * socket I/O multiplexing call. This might not be supported on all configurations
     1016 * (internal networking and iSCSI)
     1017 * and the backend needs to take appropriate action.
     1018 */
     1019#define VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT RT_BIT_32(0)
     1020
     1021/** @name Select events
     1022 * @{ */
     1023/** Readable without blocking. */
     1024#define VD_INTERFACETCPNET_EVT_READ         RT_BIT_32(0)
     1025/** Writable without blocking. */
     1026#define VD_INTERFACETCPNET_EVT_WRITE        RT_BIT_32(1)
     1027/** Error condition, hangup, exception or similar. */
     1028#define VD_INTERFACETCPNET_EVT_ERROR        RT_BIT_32(2)
     1029/** Mask of the valid bits. */
     1030#define VD_INTERFACETCPNET_EVT_VALID_MASK   UINT32_C(0x00000007)
     1031/** @} */
    10071032
    10081033/**
     
    10241049
    10251050    /**
     1051     * Creates a socket. The socket is not connected if this succeeds.
     1052     *
     1053     * @return  iprt status code.
     1054     * @retval  VERR_NOT_SUPPORTED if the combination of flags is not supported.
     1055     * @param   fFlags    Combination of the VD_INTERFACETCPNET_CONNECT_* #defines.
     1056     * @param   pSock     Where to store the handle.
     1057     */
     1058    DECLR3CALLBACKMEMBER(int, pfnSocketCreate, (uint32_t fFlags, PVDSOCKET pSock));
     1059
     1060    /**
     1061     * Destroys the socket.
     1062     *
     1063     * @return iprt status code.
     1064     * @param  Sock       Socket descriptor.
     1065     */
     1066    DECLR3CALLBACKMEMBER(int, pfnSocketDestroy, (VDSOCKET Sock));
     1067
     1068    /**
    10261069     * Connect as a client to a TCP port.
    10271070     *
    10281071     * @return  iprt status code.
     1072     * @param   Sock            Socket descriptor.
    10291073     * @param   pszAddress      The address to connect to.
    10301074     * @param   uPort           The port to connect to.
    1031      * @param   pSock           Where to store the handle to the established connection.
    1032      */
    1033     DECLR3CALLBACKMEMBER(int, pfnClientConnect, (const char *pszAddress, uint32_t uPort, PRTSOCKET pSock));
     1075     */
     1076    DECLR3CALLBACKMEMBER(int, pfnClientConnect, (VDSOCKET Sock, const char *pszAddress, uint32_t uPort));
    10341077
    10351078    /**
     
    10391082     * @param   Sock            Socket descriptor.
    10401083     */
    1041     DECLR3CALLBACKMEMBER(int, pfnClientClose, (RTSOCKET Sock));
     1084    DECLR3CALLBACKMEMBER(int, pfnClientClose, (VDSOCKET Sock));
     1085
     1086    /**
     1087     * Returns whether the socket is currently connected to the client.
     1088     *
     1089     * @returns true if the socket is connected.
     1090     *          false otherwise.
     1091     * @param   Sock        Socket descriptor.
     1092     */
     1093    DECLR3CALLBACKMEMBER(bool, pfnIsClientConnected, (VDSOCKET Sock));
    10421094
    10431095    /**
     
    10501102     *                      Use RT_INDEFINITE_WAIT to wait for ever.
    10511103     */
    1052     DECLR3CALLBACKMEMBER(int, pfnSelectOne, (RTSOCKET Sock, RTMSINTERVAL cMillies));
     1104    DECLR3CALLBACKMEMBER(int, pfnSelectOne, (VDSOCKET Sock, RTMSINTERVAL cMillies));
    10531105
    10541106    /**
     
    10631115     *                      If not NULL a partial read can be done successfully.
    10641116     */
    1065     DECLR3CALLBACKMEMBER(int, pfnRead, (RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead));
     1117    DECLR3CALLBACKMEMBER(int, pfnRead, (VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead));
    10661118
    10671119    /**
     
    10731125     * @param   cbBuffer    How much to write.
    10741126     */
    1075     DECLR3CALLBACKMEMBER(int, pfnWrite, (RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer));
     1127    DECLR3CALLBACKMEMBER(int, pfnWrite, (VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer));
    10761128
    10771129    /**
     
    10821134     * @param   pSgBuf      Scatter/gather buffer to write data to socket.
    10831135     */
    1084     DECLR3CALLBACKMEMBER(int, pfnSgWrite, (RTSOCKET Sock, PCRTSGBUF pSgBuf));
     1136    DECLR3CALLBACKMEMBER(int, pfnSgWrite, (VDSOCKET Sock, PCRTSGBUF pSgBuf));
    10851137
    10861138    /**
     
    10901142     * @param   Sock        Socket descriptor.
    10911143     */
    1092     DECLR3CALLBACKMEMBER(int, pfnFlush, (RTSOCKET Sock));
     1144    DECLR3CALLBACKMEMBER(int, pfnFlush, (VDSOCKET Sock));
    10931145
    10941146    /**
     
    10991151     * @param   fEnable     When set to true enables coalescing.
    11001152     */
    1101     DECLR3CALLBACKMEMBER(int, pfnSetSendCoalescing, (RTSOCKET Sock, bool fEnable));
     1153    DECLR3CALLBACKMEMBER(int, pfnSetSendCoalescing, (VDSOCKET Sock, bool fEnable));
    11021154
    11031155    /**
     
    11081160     * @param   pAddr       Where to store the local address on success.
    11091161     */
    1110     DECLR3CALLBACKMEMBER(int, pfnGetLocalAddress, (RTSOCKET Sock, PRTNETADDR pAddr));
     1162    DECLR3CALLBACKMEMBER(int, pfnGetLocalAddress, (VDSOCKET Sock, PRTNETADDR pAddr));
    11111163
    11121164    /**
     
    11171169     * @param   pAddr       Where to store the peer address on success.
    11181170     */
    1119     DECLR3CALLBACKMEMBER(int, pfnGetPeerAddress, (RTSOCKET Sock, PRTNETADDR pAddr));
     1171    DECLR3CALLBACKMEMBER(int, pfnGetPeerAddress, (VDSOCKET Sock, PRTNETADDR pAddr));
     1172
     1173    /**
     1174     * Socket I/O multiplexing - extended version which can be woken up.
     1175     * Checks if the socket is ready for reading or writing.
     1176     *
     1177     * @return  iprt status code.
     1178     * @retval  VERR_INTERRUPTED if the thread was woken up by a pfnPoke call.
     1179     * @param   Sock        Socket descriptor.
     1180     * @param   pfEvents    Where to store the received events.
     1181     * @param   cMillies    Number of milliseconds to wait for the socket.
     1182     *                      Use RT_INDEFINITE_WAIT to wait for ever.
     1183     */
     1184    DECLR3CALLBACKMEMBER(int, pfnSelectOneEx, (VDSOCKET Sock, uint32_t *pfEvents, RTMSINTERVAL cMillies));
     1185
     1186    /**
     1187     * Wakes up the thread waiting in pfnSelectOneEx.
     1188     *
     1189     * @return iprt status code.
     1190     * @param  Sock        Socket descriptor.
     1191     */
     1192    DECLR3CALLBACKMEMBER(int, pfnPoke, (VDSOCKET Sock));
    11201193
    11211194} VDINTERFACETCPNET, *PVDINTERFACETCPNET;
  • trunk/src/VBox/Devices/Storage/DrvVD.cpp

    r30468 r31098  
    3333#include <iprt/semaphore.h>
    3434#include <iprt/sg.h>
     35#include <iprt/poll.h>
     36#include <iprt/pipe.h>
    3537
    3638#ifdef VBOX_WITH_INIP
     
    289291    PDRVVDSTORAGEBACKEND pStorageBackend = (PDRVVDSTORAGEBACKEND)pvTemplateUser;
    290292
     293    LogFlowFunc(("pDrvIns=%#p pvTemplateUser=%#p pvUser=%#p rcReq\n",
     294                 pDrvIns, pvTemplateUser, pvUser, rcReq));
     295
    291296    if (pStorageBackend->fSyncIoPending)
    292297    {
     298        Assert(!pvUser);
    293299        pStorageBackend->rcReqLast      = rcReq;
    294300        pStorageBackend->fSyncIoPending = false;
     
    298304    {
    299305        int rc;
     306
     307        AssertPtr(pvUser);
    300308
    301309        AssertPtr(pStorageBackend->pfnCompleted);
     
    440448    PPDMASYNCCOMPLETIONTASK pTask;
    441449
     450    LogFlowFunc(("pvUser=%#p pStorage=%#p\n", pvUser, pStorage));
     451
    442452    Assert(!pStorageBackend->fSyncIoPending);
    443453    ASMAtomicXchgBool(&pStorageBackend->fSyncIoPending, true);
     
    450460    {
    451461        /* Wait */
     462        LogFlowFunc(("Waiting for flush to complete\n"));
    452463        rc = RTSemEventWait(pStorageBackend->EventSem, RT_INDEFINITE_WAIT);
    453464        AssertRC(rc);
     
    592603} INIPSOCKADDRUNION;
    593604
    594 static DECLCALLBACK(int) drvvdINIPFlush(RTSOCKET Sock);
     605typedef struct INIPSOCKET
     606{
     607    int hSock;
     608} INIPSOCKET, *PINIPSOCKET;
     609
     610static DECLCALLBACK(int) drvvdINIPFlush(VDSOCKET Sock);
     611
     612/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
     613static DECLCALLBACK(int) drvvdINIPSocketCreate(uint32_t fFlags, PVDSOCKET pSock)
     614{
     615    PINIPSOCKET pSocketInt = NULL;
     616
     617    /*
     618     * The extended select method is not supported because it is impossible to wakeup
     619     * the thread.
     620     */
     621    if (fFlags & VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT)
     622        return VERR_NOT_SUPPORTED;
     623
     624    pSocketInt = (PINIPSOCKET)RTMemAllocZ(sizeof(INIPSOCKET));
     625    if (pSocketInt)
     626    {
     627        pSocketInt->hSock = INT32_MAX;
     628        *pSock = (VDSOCKET)pSocketInt;
     629        return VINF_SUCCESS;
     630    }
     631
     632    return VERR_NO_MEMORY;
     633}
     634
     635/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
     636static DECLCALLBACK(int) drvvdINIPSocketDestroy(VDSOCKET Sock)
     637{
     638    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
     639
     640    RTMemFree(pSocketInt);
     641    return VINF_SUCCESS;
     642}
    595643
    596644/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
    597 static DECLCALLBACK(int) drvvdINIPClientConnect(const char *pszAddress, uint32_t uPort, PRTSOCKET pSock)
     645static DECLCALLBACK(int) drvvdINIPClientConnect(VDSOCKET Sock, const char *pszAddress, uint32_t uPort)
    598646{
    599647    int rc = VINF_SUCCESS;
    600     /* First check whether lwIP is set up in this VM instance. */
     648    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
     649
     650    /* Check whether lwIP is set up in this VM instance. */
    601651    if (!DevINIPConfigured())
    602652    {
     
    613663    }
    614664    /* Create socket and connect. */
    615     int Sock = lwip_socket(PF_INET, SOCK_STREAM, 0);
    616     if (Sock != -1)
     665    int iSock = lwip_socket(PF_INET, SOCK_STREAM, 0);
     666    if (iSock != -1)
    617667    {
    618668        struct sockaddr_in InAddr = {0};
     
    620670        InAddr.sin_port = htons(uPort);
    621671        InAddr.sin_addr = ip;
    622         if (!lwip_connect(Sock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
    623         {
    624             *pSock = (RTSOCKET)Sock;
     672        if (!lwip_connect(iSock, (struct sockaddr *)&InAddr, sizeof(InAddr)))
     673        {
     674            pSocketInt->hSock = iSock;
    625675            return VINF_SUCCESS;
    626676        }
    627677        rc = VERR_NET_CONNECTION_REFUSED; /* @todo real solution needed */
    628         lwip_close(Sock);
     678        lwip_close(iSock);
    629679    }
    630680    else
     
    634684
    635685/** @copydoc VDINTERFACETCPNET::pfnClientClose */
    636 static DECLCALLBACK(int) drvvdINIPClientClose(RTSOCKET Sock)
    637 {
    638     lwip_close((uintptr_t)Sock);
     686static DECLCALLBACK(int) drvvdINIPClientClose(VDSOCKET Sock)
     687{
     688    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
     689
     690    lwip_close(pSocketInt->hSock);
     691    pSocketInt->hSock = INT32_MAX;
    639692    return VINF_SUCCESS; /** @todo real solution needed */
    640693}
    641694
     695/** @copydoc VDINTERFACETCPNET::pfnIsClientConnected */
     696static DECLCALLBACK(bool) drvvdINIPIsClientConnected(VDSOCKET Sock)
     697{
     698    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
     699
     700    return pSocketInt->hSock != INT32_MAX;
     701}
     702
    642703/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
    643 static DECLCALLBACK(int) drvvdINIPSelectOne(RTSOCKET Sock, RTMSINTERVAL cMillies)
    644 {
     704static DECLCALLBACK(int) drvvdINIPSelectOne(VDSOCKET Sock, RTMSINTERVAL cMillies)
     705{
     706    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
    645707    fd_set fdsetR;
    646708    FD_ZERO(&fdsetR);
     
    650712    int rc;
    651713    if (cMillies == RT_INDEFINITE_WAIT)
    652         rc = lwip_select((uintptr_t)Sock + 1, &fdsetR, NULL, &fdsetE, NULL);
     714        rc = lwip_select(pSocketInt->hSock + 1, &fdsetR, NULL, &fdsetE, NULL);
    653715    else
    654716    {
     
    656718        timeout.tv_sec = cMillies / 1000;
    657719        timeout.tv_usec = (cMillies % 1000) * 1000;
    658         rc = lwip_select((uintptr_t)Sock + 1, &fdsetR, NULL, &fdsetE, &timeout);
     720        rc = lwip_select(pSocketInt->hSock + 1, &fdsetR, NULL, &fdsetE, &timeout);
    659721    }
    660722    if (rc > 0)
     
    666728
    667729/** @copydoc VDINTERFACETCPNET::pfnRead */
    668 static DECLCALLBACK(int) drvvdINIPRead(RTSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
    669 {
     730static DECLCALLBACK(int) drvvdINIPRead(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
     731{
     732    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
     733
    670734    /* Do params checking */
    671735    if (!pvBuffer || !cbBuffer)
     
    686750         * needed it, so I added it here, too). Didn't investigate if this
    687751         * really has issues. Better be safe than sorry. */
    688         ssize_t cbBytesRead = lwip_recv((uintptr_t)Sock, (char *)pvBuffer + cbRead,
     752        ssize_t cbBytesRead = lwip_recv(pSocketInt->hSock, (char *)pvBuffer + cbRead,
    689753                                        RT_MIN(cbToRead, 32768), 0);
    690754        if (cbBytesRead < 0)
     
    712776
    713777/** @copydoc VDINTERFACETCPNET::pfnWrite */
    714 static DECLCALLBACK(int) drvvdINIPWrite(RTSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
    715 {
     778static DECLCALLBACK(int) drvvdINIPWrite(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
     779{
     780    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
     781
    716782    do
    717783    {
     
    720786         * don't get any wraparounds. This should be moved to DevINIP
    721787         * stack interface once that's implemented. */
    722         ssize_t cbWritten = lwip_send((uintptr_t)Sock, (void *)pvBuffer,
     788        ssize_t cbWritten = lwip_send(pSocketInt->hSock, (void *)pvBuffer,
    723789                                      RT_MIN(cbBuffer, 32768), 0);
    724790        if (cbWritten < 0)
     
    734800
    735801/** @copydoc VDINTERFACETCPNET::pfnSgWrite */
    736 static DECLCALLBACK(int) drvvdINIPSgWrite(RTSOCKET Sock, PCRTSGBUF pSgBuf)
     802static DECLCALLBACK(int) drvvdINIPSgWrite(VDSOCKET Sock, PCRTSGBUF pSgBuf)
    737803{
    738804    int rc = VINF_SUCCESS;
     
    754820
    755821/** @copydoc VDINTERFACETCPNET::pfnFlush */
    756 static DECLCALLBACK(int) drvvdINIPFlush(RTSOCKET Sock)
    757 {
     822static DECLCALLBACK(int) drvvdINIPFlush(VDSOCKET Sock)
     823{
     824    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
     825
    758826    int fFlag = 1;
    759     lwip_setsockopt((uintptr_t)Sock, IPPROTO_TCP, TCP_NODELAY,
     827    lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
    760828                    (const char *)&fFlag, sizeof(fFlag));
    761829    fFlag = 0;
    762     lwip_setsockopt((uintptr_t)Sock, IPPROTO_TCP, TCP_NODELAY,
     830    lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
    763831                    (const char *)&fFlag, sizeof(fFlag));
    764832    return VINF_SUCCESS;
     
    766834
    767835/** @copydoc VDINTERFACETCPNET::pfnSetSendCoalescing */
    768 static DECLCALLBACK(int) drvvdINIPSetSendCoalescing(RTSOCKET Sock, bool fEnable)
    769 {
     836static DECLCALLBACK(int) drvvdINIPSetSendCoalescing(VDSOCKET Sock, bool fEnable)
     837{
     838    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
     839
    770840    int fFlag = fEnable ? 0 : 1;
    771     lwip_setsockopt((uintptr_t)Sock, IPPROTO_TCP, TCP_NODELAY,
     841    lwip_setsockopt(pSocketInt->hSock, IPPROTO_TCP, TCP_NODELAY,
    772842                    (const char *)&fFlag, sizeof(fFlag));
    773843    return VINF_SUCCESS;
     
    775845
    776846/** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */
    777 static DECLCALLBACK(int) drvvdINIPGetLocalAddress(RTSOCKET Sock, PRTNETADDR pAddr)
    778 {
     847static DECLCALLBACK(int) drvvdINIPGetLocalAddress(VDSOCKET Sock, PRTNETADDR pAddr)
     848{
     849    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
    779850    INIPSOCKADDRUNION u;
    780851    socklen_t cbAddr = sizeof(u);
    781852    RT_ZERO(u);
    782     if (!lwip_getsockname((uintptr_t)Sock, &u.Addr, &cbAddr))
     853    if (!lwip_getsockname(pSocketInt->hSock, &u.Addr, &cbAddr))
    783854    {
    784855        /*
     
    801872
    802873/** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */
    803 static DECLCALLBACK(int) drvvdINIPGetPeerAddress(RTSOCKET Sock, PRTNETADDR pAddr)
    804 {
     874static DECLCALLBACK(int) drvvdINIPGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr)
     875{
     876    PINIPSOCKET pSocketInt = (PINIPSOCKET)Sock;
    805877    INIPSOCKADDRUNION u;
    806878    socklen_t cbAddr = sizeof(u);
    807879    RT_ZERO(u);
    808     if (!lwip_getpeername((uintptr_t)Sock, &u.Addr, &cbAddr))
     880    if (!lwip_getpeername(pSocketInt->hSock, &u.Addr, &cbAddr))
    809881    {
    810882        /*
     
    825897    return VERR_NET_OPERATION_NOT_SUPPORTED;
    826898}
     899
     900/** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */
     901static DECLCALLBACK(int) drvvdINIPSelectOneEx(VDSOCKET Sock, uint32_t *pfEvents, RTMSINTERVAL cMillies)
     902{
     903    AssertMsgFailed(("Not supported!\n"));
     904    return VERR_NOT_SUPPORTED;
     905}
     906
     907/** @copydoc VDINTERFACETCPNET::pfnPoke */
     908static DECLCALLBACK(int) drvvdINIPPoke(VDSOCKET Sock)
     909{
     910    AssertMsgFailed(("Not supported!\n"));
     911    return VERR_NOT_SUPPORTED;
     912}
     913
    827914#endif /* VBOX_WITH_INIP */
     915
     916
     917/*******************************************************************************
     918*   VD TCP network stack interface implementation - Host TCP case              *
     919*******************************************************************************/
     920
     921/**
     922 * Socket data.
     923 */
     924typedef struct VDSOCKETINT
     925{
     926    /** IPRT socket handle. */
     927    RTSOCKET      hSocket;
     928    /** Pollset with the wakeup pipe and socket. */
     929    RTPOLLSET     hPollSet;
     930    /** Pipe endpoint - read (in the pollset). */
     931    RTPIPE        hPipeR;
     932    /** Pipe endpoint - write. */
     933    RTPIPE        hPipeW;
     934    /** Flag whether the thread was woken up. */
     935    volatile bool fWokenUp;
     936    /** Flag whether the thread is waiting in the select call. */
     937    volatile bool fWaiting;
     938} VDSOCKETINT, *PVDSOCKETINT;
     939
     940/** Pollset id of the socket. */
     941#define VDSOCKET_POLL_ID_SOCKET 0
     942/** Pollset id of the pipe. */
     943#define VDSOCKET_POLL_ID_PIPE   1
     944
     945/** @copydoc VDINTERFACETCPNET::pfnSocketCreate */
     946static DECLCALLBACK(int) drvvdTcpSocketCreate(uint32_t fFlags, PVDSOCKET pSock)
     947{
     948    int rc = VINF_SUCCESS;
     949    int rc2 = VINF_SUCCESS;
     950    PVDSOCKETINT pSockInt = NULL;
     951
     952    pSockInt = (PVDSOCKETINT)RTMemAllocZ(sizeof(VDSOCKETINT));
     953    if (!pSockInt)
     954        return VERR_NO_MEMORY;
     955
     956    pSockInt->hSocket  = NIL_RTSOCKET;
     957    pSockInt->hPollSet = NIL_RTPOLLSET;
     958    pSockInt->hPipeR   = NIL_RTPIPE;
     959    pSockInt->hPipeW   = NIL_RTPIPE;
     960    pSockInt->fWokenUp = false;
     961    pSockInt->fWaiting = false;
     962
     963    if (fFlags & VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT)
     964    {
     965        /* Init pipe and pollset. */
     966        rc = RTPipeCreate(&pSockInt->hPipeR, &pSockInt->hPipeW, 0);
     967        if (RT_SUCCESS(rc))
     968        {
     969            rc = RTPollSetCreate(&pSockInt->hPollSet);
     970            if (RT_SUCCESS(rc))
     971            {
     972                rc = RTPollSetAddPipe(pSockInt->hPollSet, pSockInt->hPipeR,
     973                                      RTPOLL_EVT_READ, VDSOCKET_POLL_ID_PIPE);
     974                if (RT_SUCCESS(rc))
     975                {
     976                    *pSock = pSockInt;
     977                    return VINF_SUCCESS;
     978                }
     979
     980                RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
     981                rc2 = RTPollSetDestroy(pSockInt->hPollSet);
     982                AssertRC(rc2);
     983            }
     984
     985            rc2 = RTPipeClose(pSockInt->hPipeR);
     986            AssertRC(rc2);
     987            rc2 = RTPipeClose(pSockInt->hPipeW);
     988            AssertRC(rc2);
     989        }
     990    }
     991
     992    RTMemFree(pSockInt);
     993
     994    return rc;
     995}
     996
     997/** @copydoc VDINTERFACETCPNET::pfnSocketDestroy */
     998static DECLCALLBACK(int) drvvdTcpSocketDestroy(VDSOCKET Sock)
     999{
     1000    int rc = VINF_SUCCESS;
     1001    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1002
     1003    /* Destroy the pipe and pollset if necessary. */
     1004    if (pSockInt->hPollSet != NIL_RTPOLLSET)
     1005    {
     1006        if (pSockInt->hSocket != NIL_RTSOCKET)
     1007        {
     1008            rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
     1009            AssertRC(rc);
     1010        }
     1011        rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_PIPE);
     1012        AssertRC(rc);
     1013        rc = RTPollSetDestroy(pSockInt->hPollSet);
     1014        AssertRC(rc);
     1015        rc = RTPipeClose(pSockInt->hPipeR);
     1016        AssertRC(rc);
     1017        rc = RTPipeClose(pSockInt->hPipeW);
     1018        AssertRC(rc);
     1019    }
     1020
     1021    if (pSockInt->hSocket != NIL_RTSOCKET)
     1022        rc = RTTcpClientClose(pSockInt->hSocket);
     1023
     1024    RTMemFree(pSockInt);
     1025
     1026    return rc;
     1027}
     1028
     1029/** @copydoc VDINTERFACETCPNET::pfnClientConnect */
     1030static DECLCALLBACK(int) drvvdTcpClientConnect(VDSOCKET Sock, const char *pszAddress, uint32_t uPort)
     1031{
     1032    int rc = VINF_SUCCESS;
     1033    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1034
     1035    rc = RTTcpClientConnect(pszAddress, uPort, &pSockInt->hSocket);
     1036    if (RT_SUCCESS(rc))
     1037    {
     1038        /* Add to the pollset if required. */
     1039        if (pSockInt->hPollSet != NIL_RTPOLLSET)
     1040        {
     1041            rc = RTPollSetAddSocket(pSockInt->hPollSet, pSockInt->hSocket,
     1042                                    RTPOLL_EVT_READ | /*RTPOLL_EVT_WRITE |*/ RTPOLL_EVT_ERROR,
     1043                                    VDSOCKET_POLL_ID_SOCKET);
     1044
     1045            if (RT_SUCCESS(rc))
     1046                return VINF_SUCCESS;
     1047        }
     1048
     1049        rc = RTTcpClientClose(pSockInt->hSocket);
     1050    }
     1051
     1052    return rc;
     1053}
     1054
     1055/** @copydoc VDINTERFACETCPNET::pfnClientClose */
     1056static DECLCALLBACK(int) drvvdTcpClientClose(VDSOCKET Sock)
     1057{
     1058    int rc = VINF_SUCCESS;
     1059    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1060
     1061    if (pSockInt->hPollSet != NIL_RTPOLLSET)
     1062    {
     1063        rc = RTPollSetRemove(pSockInt->hPollSet, VDSOCKET_POLL_ID_SOCKET);
     1064        AssertRC(rc);
     1065    }
     1066
     1067    rc = RTTcpClientClose(pSockInt->hSocket);
     1068    pSockInt->hSocket = NIL_RTSOCKET;
     1069
     1070    return rc;
     1071}
     1072
     1073/** @copydoc VDINTERFACETCPNET::pfnIsClientConnected */
     1074static DECLCALLBACK(bool) drvvdTcpIsClientConnected(VDSOCKET Sock)
     1075{
     1076    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1077
     1078    return pSockInt->hSocket != NIL_RTSOCKET;
     1079}
     1080
     1081/** @copydoc VDINTERFACETCPNET::pfnSelectOne */
     1082static DECLCALLBACK(int) drvvdTcpSelectOne(VDSOCKET Sock, RTMSINTERVAL cMillies)
     1083{
     1084    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1085
     1086    return RTTcpSelectOne(pSockInt->hSocket, cMillies);
     1087}
     1088
     1089/** @copydoc VDINTERFACETCPNET::pfnRead */
     1090static DECLCALLBACK(int) drvvdTcpRead(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
     1091{
     1092    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1093
     1094    return RTTcpRead(pSockInt->hSocket, pvBuffer, cbBuffer, pcbRead);
     1095}
     1096
     1097/** @copydoc VDINTERFACETCPNET::pfnWrite */
     1098static DECLCALLBACK(int) drvvdTcpWrite(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
     1099{
     1100    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1101
     1102    return RTTcpWrite(pSockInt->hSocket, pvBuffer, cbBuffer);
     1103}
     1104
     1105/** @copydoc VDINTERFACETCPNET::pfnSgWrite */
     1106static DECLCALLBACK(int) drvvdTcpSgWrite(VDSOCKET Sock, PCRTSGBUF pSgBuf)
     1107{
     1108    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1109
     1110    return RTTcpSgWrite(pSockInt->hSocket, pSgBuf);
     1111}
     1112
     1113/** @copydoc VDINTERFACETCPNET::pfnFlush */
     1114static DECLCALLBACK(int) drvvdTcpFlush(VDSOCKET Sock)
     1115{
     1116    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1117
     1118    return RTTcpFlush(pSockInt->hSocket);
     1119}
     1120
     1121/** @copydoc VDINTERFACETCPNET::pfnSetSendCoalescing */
     1122static DECLCALLBACK(int) drvvdTcpSetSendCoalescing(VDSOCKET Sock, bool fEnable)
     1123{
     1124    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1125
     1126    return RTTcpSetSendCoalescing(pSockInt->hSocket, fEnable);
     1127}
     1128
     1129/** @copydoc VDINTERFACETCPNET::pfnGetLocalAddress */
     1130static DECLCALLBACK(int) drvvdTcpGetLocalAddress(VDSOCKET Sock, PRTNETADDR pAddr)
     1131{
     1132    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1133
     1134    return RTTcpGetLocalAddress(pSockInt->hSocket, pAddr);
     1135}
     1136
     1137/** @copydoc VDINTERFACETCPNET::pfnGetPeerAddress */
     1138static DECLCALLBACK(int) drvvdTcpGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr)
     1139{
     1140    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1141
     1142    return RTTcpGetPeerAddress(pSockInt->hSocket, pAddr);
     1143}
     1144
     1145/** @copydoc VDINTERFACETCPNET::pfnSelectOneEx */
     1146static DECLCALLBACK(int) drvvdTcpSelectOneEx(VDSOCKET Sock, uint32_t *pfEvents, RTMSINTERVAL cMillies)
     1147{
     1148    int rc = VINF_SUCCESS;
     1149    uint32_t id = 0;
     1150    uint32_t fEvents = 0;
     1151    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1152
     1153    *pfEvents = 0;
     1154
     1155    ASMAtomicXchgBool(&pSockInt->fWaiting, true);
     1156    if (ASMAtomicXchgBool(&pSockInt->fWokenUp, false))
     1157    {
     1158        ASMAtomicXchgBool(&pSockInt->fWaiting, false);
     1159        return VERR_INTERRUPTED;
     1160    }
     1161
     1162    rc = RTPoll(pSockInt->hPollSet, cMillies, &fEvents, &id);
     1163    Assert(RT_SUCCESS(rc) || rc == VERR_TIMEOUT);
     1164
     1165    ASMAtomicXchgBool(&pSockInt->fWaiting, false);
     1166
     1167    if (RT_SUCCESS(rc))
     1168    {
     1169        if (id == VDSOCKET_POLL_ID_SOCKET)
     1170        {
     1171            fEvents &= RTPOLL_EVT_VALID_MASK;
     1172
     1173            if (fEvents & RTPOLL_EVT_READ)
     1174                *pfEvents |= VD_INTERFACETCPNET_EVT_READ;
     1175            if (fEvents & RTPOLL_EVT_WRITE)
     1176                *pfEvents |= VD_INTERFACETCPNET_EVT_WRITE;
     1177            if (fEvents & RTPOLL_EVT_ERROR)
     1178                *pfEvents |= VD_INTERFACETCPNET_EVT_ERROR;
     1179        }
     1180        else
     1181        {
     1182            size_t cbRead = 0;
     1183            uint8_t abBuf[10];
     1184            Assert(id == VDSOCKET_POLL_ID_PIPE);
     1185            Assert((fEvents & RTPOLL_EVT_VALID_MASK) == RTPOLL_EVT_READ);
     1186
     1187            /* We got interrupted, drain the pipe. */
     1188            rc = RTPipeRead(pSockInt->hPipeR, abBuf, sizeof(abBuf), &cbRead);
     1189            AssertRC(rc);
     1190
     1191            ASMAtomicXchgBool(&pSockInt->fWokenUp, false);
     1192
     1193            rc = VERR_INTERRUPTED;
     1194        }
     1195    }
     1196
     1197    return rc;
     1198}
     1199
     1200/** @copydoc VDINTERFACETCPNET::pfnPoke */
     1201static DECLCALLBACK(int) drvvdTcpPoke(VDSOCKET Sock)
     1202{
     1203    int rc = VINF_SUCCESS;
     1204    size_t cbWritten = 0;
     1205    PVDSOCKETINT pSockInt = (PVDSOCKETINT)Sock;
     1206
     1207    ASMAtomicXchgBool(&pSockInt->fWokenUp, true);
     1208
     1209    if (ASMAtomicReadBool(&pSockInt->fWaiting))
     1210    {
     1211        rc = RTPipeWrite(pSockInt->hPipeW, "", 1, &cbWritten);
     1212        Assert(RT_SUCCESS(rc) || cbWritten == 0);
     1213    }
     1214
     1215    return VINF_SUCCESS;
     1216}
    8281217
    8291218
     
    14101799            pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
    14111800            pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
    1412             pThis->VDITcpNetCallbacks.pfnClientConnect = RTTcpClientConnect;
    1413             pThis->VDITcpNetCallbacks.pfnClientClose = RTTcpClientClose;
    1414             pThis->VDITcpNetCallbacks.pfnSelectOne = RTTcpSelectOne;
    1415             pThis->VDITcpNetCallbacks.pfnRead = RTTcpRead;
    1416             pThis->VDITcpNetCallbacks.pfnWrite = RTTcpWrite;
    1417             pThis->VDITcpNetCallbacks.pfnSgWrite = RTTcpSgWrite;
    1418             pThis->VDITcpNetCallbacks.pfnFlush = RTTcpFlush;
    1419             pThis->VDITcpNetCallbacks.pfnSetSendCoalescing = RTTcpSetSendCoalescing;
    1420             pThis->VDITcpNetCallbacks.pfnGetLocalAddress = RTTcpGetLocalAddress;
    1421             pThis->VDITcpNetCallbacks.pfnGetPeerAddress = RTTcpGetPeerAddress;
     1801            pThis->VDITcpNetCallbacks.pfnSocketCreate = drvvdTcpSocketCreate;
     1802            pThis->VDITcpNetCallbacks.pfnSocketDestroy = drvvdTcpSocketDestroy;
     1803            pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdTcpClientConnect;
     1804            pThis->VDITcpNetCallbacks.pfnIsClientConnected = drvvdTcpIsClientConnected;
     1805            pThis->VDITcpNetCallbacks.pfnClientClose = drvvdTcpClientClose;
     1806            pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdTcpSelectOne;
     1807            pThis->VDITcpNetCallbacks.pfnRead = drvvdTcpRead;
     1808            pThis->VDITcpNetCallbacks.pfnWrite = drvvdTcpWrite;
     1809            pThis->VDITcpNetCallbacks.pfnSgWrite = drvvdTcpSgWrite;
     1810            pThis->VDITcpNetCallbacks.pfnFlush = drvvdTcpFlush;
     1811            pThis->VDITcpNetCallbacks.pfnSetSendCoalescing = drvvdTcpSetSendCoalescing;
     1812            pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdTcpGetLocalAddress;
     1813            pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdTcpGetPeerAddress;
     1814            pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdTcpSelectOneEx;
     1815            pThis->VDITcpNetCallbacks.pfnPoke = drvvdTcpPoke;
    14221816        }
    14231817        else
     
    14291823            pThis->VDITcpNetCallbacks.cbSize = sizeof(VDINTERFACETCPNET);
    14301824            pThis->VDITcpNetCallbacks.enmInterface = VDINTERFACETYPE_TCPNET;
     1825            pThis->VDITcpNetCallbacks.pfnSocketCreate = drvvdINIPSocketCreate;
     1826            pThis->VDITcpNetCallbacks.pfnSocketDestroy = drvvdINIPSocketDestroy;
    14311827            pThis->VDITcpNetCallbacks.pfnClientConnect = drvvdINIPClientConnect;
    14321828            pThis->VDITcpNetCallbacks.pfnClientClose = drvvdINIPClientClose;
     1829            pThis->VDITcpNetCallbacks.pfnIsClientConnected = drvvdINIPIsClientConnected;
    14331830            pThis->VDITcpNetCallbacks.pfnSelectOne = drvvdINIPSelectOne;
    14341831            pThis->VDITcpNetCallbacks.pfnRead = drvvdINIPRead;
     
    14391836            pThis->VDITcpNetCallbacks.pfnGetLocalAddress = drvvdINIPGetLocalAddress;
    14401837            pThis->VDITcpNetCallbacks.pfnGetPeerAddress = drvvdINIPGetPeerAddress;
     1838            pThis->VDITcpNetCallbacks.pfnSelectOneEx = drvvdINIPSelectOneEx;
     1839            pThis->VDITcpNetCallbacks.pfnPoke = drvvdINIPPoke;
    14411840#endif /* VBOX_WITH_INIP */
    14421841        }
  • trunk/src/VBox/Devices/Storage/ISCSIHDDCore.cpp

    r30941 r31098  
    266266*   Structures and Typedefs                                                    *
    267267*******************************************************************************/
     268
     269/**
     270 * iSCSI login negotiation parameter
     271 */
     272typedef struct ISCSIPARAMETER
     273{
     274    /** Name of the parameter. */
     275    const char *pszParamName;
     276    /** Value of the parameter. */
     277    const char *pszParamValue;
     278    /** Length of the binary parameter. 0=zero-terminated string. */
     279    size_t cbParamValue;
     280} ISCSIPARAMETER;
     281
     282
     283/**
     284 * iSCSI Response PDU buffer (scatter).
     285 */
     286typedef struct ISCSIRES
     287{
     288    /** Length of PDU segment. */
     289    size_t cbSeg;
     290    /** Pointer to PDU segment. */
     291    void *pvSeg;
     292} ISCSIRES;
     293/** Pointer to an iSCSI Response PDU buffer. */
     294typedef ISCSIRES *PISCSIRES;
     295/** Pointer to a const iSCSI Response PDU buffer. */
     296typedef ISCSIRES const *PCISCSIRES;
     297
     298
    268299/**
    269300 * iSCSI Request PDU buffer (gather).
     
    281312typedef ISCSIREQ const *PCISCSIREQ;
    282313
     314
     315/**
     316 * SCSI transfer directions.
     317 */
     318typedef enum SCSIXFER
     319{
     320    SCSIXFER_NONE = 0,
     321    SCSIXFER_TO_TARGET,
     322    SCSIXFER_FROM_TARGET,
     323    SCSIXFER_TO_FROM_TARGET
     324} SCSIXFER, *PSCSIXFER;
     325
     326
     327/**
     328 * SCSI request structure.
     329 */
     330typedef struct SCSIREQ
     331{
     332    /** Transfer direction. */
     333    SCSIXFER        enmXfer;
     334    /** Length of command block. */
     335    size_t          cbCmd;
     336    /** Length of Initiator2Target data buffer. */
     337    size_t          cbI2TData;
     338    /** Length of Target2Initiator data buffer. */
     339    size_t          cbT2IData;
     340    /** Length of sense buffer. */
     341    size_t          cbSense;
     342    /** Completion status of the command. */
     343    uint8_t         status;
     344    /** Pointer to command block. */
     345    void           *pvCmd;
     346    /** Pointer to Initiator2Target data buffer. */
     347    const void     *pcvI2TData;
     348    /** Pointer to Target2Initiator data buffer. */
     349    void           *pvT2IData;
     350    /** Pointer to sense buffer. */
     351    void           *pvSense;
     352} SCSIREQ, *PSCSIREQ;
     353
     354
     355typedef enum ISCSICMDTYPE
     356{
     357    /** Process a SCSI request. */
     358    ISCSICMDTYPE_REQ = 0,
     359    /** Call a function in the I/O thread. */
     360    ISCSICMDTYPE_EXEC,
     361    /** Usual 32bit hack. */
     362    ISCSICMDTYPE_32BIT_HACK = 0x7fffffff
     363} ISCSICMDTYPE;
     364
     365
     366/** The command completion function. */
     367typedef DECLCALLBACK(void) FNISCSICMDCOMPLETED(void *pvUser);
     368/** Pointer to a command completion function. */
     369typedef FNISCSICMDCOMPLETED *PFNISCSICMDCOMPLETED;
     370
     371/** The command execution function. */
     372typedef DECLCALLBACK(int) FNISCSIEXEC(void *pvUser);
     373/** Pointer to a command execution function. */
     374typedef FNISCSIEXEC *PFNISCSIEXEC;
     375
     376/**
     377 * iSCSI command.
     378 * Used to forward requests to the I/O thread
     379 * if existing.
     380 */
     381typedef struct ISCSICMD
     382{
     383    /** Next one in the list. */
     384    struct ISCSICMD *pNext;
     385    /** Command to execute. */
     386    ISCSICMDTYPE     enmCmdType;
     387    /** Flag whether this is a synchronous request. */
     388    bool             fSync;
     389    /** Type dependent data - based on fSync. */
     390    union
     391    {
     392        /** Synchronous request. */
     393        struct
     394        {
     395            /** Event semaphore to signal if this is a synchronous request. */
     396            RTSEMEVENT            EventSem;
     397            /** Completion status code. */
     398            int                   rcCmd;
     399        } Sync;
     400        /** Asynchronous request. */
     401        struct
     402        {
     403            /** Completion callback. */
     404            PFNISCSICMDCOMPLETED  pfnComplete;
     405            /** Opaque user data. */
     406            void                 *pvUser;
     407        } Async;
     408    } Type;
     409    /** Command type dependent data. */
     410    union
     411    {
     412        /** Process a SCSI request. */
     413        struct
     414        {
     415            /** The SCSI request to process. */
     416            PSCSIREQ              pScsiReq;
     417        } ScsiReq;
     418        /** Call a function in the I/O thread. */
     419        struct
     420        {
     421            /** The method to execute. */
     422            PFNISCSIEXEC          pfnExec;
     423            /** User data. */
     424            void                 *pvUser;
     425        } Exec;
     426    } CmdType;
     427} ISCSICMD, *PISCSICMD;
    283428
    284429/**
     
    377522    uint32_t            uPort;
    378523    /** Socket handle of the TCP connection. */
    379     RTSOCKET            Socket;
     524    VDSOCKET            Socket;
    380525    /** Timeout for read operations on the TCP connection (in milliseconds). */
    381526    uint32_t            uReadTimeout;
     
    384529    /** Flag whether to use the host IP stack or DevINIP. */
    385530    bool                fHostIP;
     531
     532    /** Head of request queue */
     533    PISCSICMD           pScsiReqQueue;
     534    /** Mutex protecting the request queue from concurrent access. */
     535    RTSEMMUTEX          MutexReqQueue;
     536    /** I/O thread. */
     537    RTTHREAD            hThreadIo;
     538    /** Flag whether the thread should be still running. */
     539    volatile bool       fRunning;
     540    /** Flag whether extended select is supported. */
     541    bool                fExtendedSelectSupported;
    386542} ISCSIIMAGE, *PISCSIIMAGE;
    387 
    388 
    389 /**
    390  * SCSI transfer directions.
    391  */
    392 typedef enum SCSIXFER
    393 {
    394     SCSIXFER_NONE = 0,
    395     SCSIXFER_TO_TARGET,
    396     SCSIXFER_FROM_TARGET,
    397     SCSIXFER_TO_FROM_TARGET
    398 } SCSIXFER, *PSCSIXFER;
    399 
    400 
    401 /**
    402  * SCSI request structure.
    403  */
    404 typedef struct SCSIREQ
    405 {
    406     /** Transfer direction. */
    407     SCSIXFER enmXfer;
    408     /** Length of command block. */
    409     size_t cbCmd;
    410     /** Length of Initiator2Target data buffer. */
    411     size_t cbI2TData;
    412     /** Length of Target2Initiator data buffer. */
    413     size_t cbT2IData;
    414     /** Length of sense buffer. */
    415     size_t cbSense;
    416     /** Completion status of the command. */
    417     uint8_t status;
    418     /** Pointer to command block. */
    419     void *pvCmd;
    420     /** Pointer to Initiator2Target data buffer. */
    421     const void *pcvI2TData;
    422     /** Pointer to Target2Initiator data buffer. */
    423     void *pvT2IData;
    424     /** Pointer to sense buffer. */
    425     void *pvSense;
    426 } SCSIREQ, *PSCSIREQ;
    427 
    428 
    429 /**
    430  * iSCSI login negotiation parameter
    431  */
    432 typedef struct ISCSIPARAMETER
    433 {
    434     /** Name of the parameter. */
    435     const char *pszParamName;
    436     /** Value of the parameter. */
    437     const char *pszParamValue;
    438     /** Length of the binary parameter. 0=zero-terminated string. */
    439     size_t cbParamValue;
    440 } ISCSIPARAMETER;
    441 
    442 
    443 /**
    444  * iSCSI Response PDU buffer (scatter).
    445  */
    446 typedef struct ISCSIRES
    447 {
    448     /** Length of PDU segment. */
    449     size_t cbSeg;
    450     /** Pointer to PDU segment. */
    451     void *pvSeg;
    452 } ISCSIRES;
    453 /** Pointer to an iSCSI Response PDU buffer. */
    454 typedef ISCSIRES *PISCSIRES;
    455 /** Pointer to a const iSCSI Response PDU buffer. */
    456 typedef ISCSIRES const *PCISCSIRES;
    457543
    458544
     
    501587static uint32_t iscsiNewITT(PISCSIIMAGE pImage);
    502588static int iscsiSendPDU(PISCSIIMAGE pImage, PISCSIREQ paReq, uint32_t cnReq, uint32_t uFlags);
    503 static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes);
     589static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes, bool fSelect);
    504590static int drvISCSIValidatePDU(PISCSIRES paRes, uint32_t cnRes);
    505591static int iscsiTextAddKeyValue(uint8_t *pbBuf, size_t cbBuf, size_t *pcbBufCurr, const char *pcszKey, const char *pcszValue, size_t cbValue);
     
    540626}
    541627
     628DECLINLINE(bool) iscsiIsClientConnected(PISCSIIMAGE pImage)
     629{
     630    return    pImage->Socket != NIL_VDSOCKET
     631           && pImage->pInterfaceNetCallbacks->pfnIsClientConnected(pImage->Socket);
     632}
    542633
    543634static int iscsiTransportConnect(PISCSIIMAGE pImage)
     
    547638        return VERR_NET_DEST_ADDRESS_REQUIRED;
    548639
    549     rc = pImage->pInterfaceNetCallbacks->pfnClientConnect(pImage->pszHostname, pImage->uPort, &pImage->Socket);
     640    rc = pImage->pInterfaceNetCallbacks->pfnClientConnect(pImage->Socket, pImage->pszHostname, pImage->uPort);
    550641    if (RT_FAILURE(rc))
    551642    {
     
    591682
    592683
    593 static int iscsiTransportRead(PISCSIIMAGE pImage, PISCSIRES paResponse, unsigned int cnResponse)
     684static int iscsiTransportRead(PISCSIIMAGE pImage, PISCSIRES paResponse, unsigned int cnResponse, bool fSelect)
    594685{
    595686    int rc = VINF_SUCCESS;
     
    599690
    600691    LogFlowFunc(("cnResponse=%d (%s:%d)\n", cnResponse, pImage->pszHostname, pImage->uPort));
    601     if (pImage->Socket == NIL_RTSOCKET)
     692    if (!iscsiIsClientConnected(pImage))
    602693    {
    603694        /* Reconnecting makes no sense in this case, as there will be nothing
     
    622713            }
    623714            Assert(cMilliesRemaining < 1000000);
    624             rc = pImage->pInterfaceNetCallbacks->pfnSelectOne(pImage->Socket,
    625                                                               cMilliesRemaining);
    626             if (RT_FAILURE(rc))
    627                 break;
     715            if (fSelect)
     716            {
     717                rc = pImage->pInterfaceNetCallbacks->pfnSelectOne(pImage->Socket,
     718                                                                  cMilliesRemaining);
     719                if (RT_FAILURE(rc))
     720                    break;
     721            }
    628722            rc = pImage->pInterfaceNetCallbacks->pfnRead(pImage->Socket,
    629723                                                         pDst, residual,
     
    635729                /* The other end has closed the connection. */
    636730                pImage->pInterfaceNetCallbacks->pfnClientClose(pImage->Socket);
    637                 pImage->Socket = NIL_RTSOCKET;
    638731                pImage->state = ISCSISTATE_FREE;
    639732                rc = VERR_NET_CONNECTION_RESET;
     
    686779                cbSegActual = residual;
    687780            }
     781            LogFlowFunc(("cbToRead=%u residual=%u cbSegActual=%u cbActuallRead=%u\n",
     782                         cbToRead, residual, cbSegActual, cbActuallyRead));
    688783        } while (true);
    689784    }
     
    723818
    724819    LogFlowFunc(("cnRequest=%d (%s:%d)\n", cnRequest, pImage->pszHostname, pImage->uPort));
    725     if (pImage->Socket == NIL_RTSOCKET)
     820    if (!iscsiIsClientConnected(pImage))
    726821    {
    727822        /* Attempt to reconnect if the connection was previously broken. */
     
    791886
    792887    /* Clean up previous connection data. */
    793     if (pImage->Socket != NIL_RTSOCKET)
     888    if (iscsiIsClientConnected(pImage))
    794889    {
    795890        pImage->pInterfaceNetCallbacks->pfnClientClose(pImage->Socket);
    796         pImage->Socket = NIL_RTSOCKET;
    797891    }
    798892    if (pImage->pszHostname)
     
    870964    if (RT_SUCCESS(rc))
    871965    {
    872         if (pImage->Socket == NIL_RTSOCKET)
     966        if (!iscsiIsClientConnected(pImage))
    873967            rc = iscsiTransportConnect(pImage);
    874968    }
     
    893987
    894988    LogFlowFunc(("(%s:%d)\n", pImage->pszHostname, pImage->uPort));
    895     if (pImage->Socket != NIL_RTSOCKET)
     989    if (iscsiIsClientConnected(pImage))
    896990    {
    897991        rc = pImage->pInterfaceNetCallbacks->pfnClientClose(pImage->Socket);
    898         pImage->Socket = NIL_RTSOCKET;
    899992    }
    900993    else
     
    9121005 * @param   pImage      The iSCSI connection state to be used.
    9131006 */
    914 static int iscsiAttach(PISCSIIMAGE pImage)
     1007static int iscsiAttach(void *pvUser)
    9151008{
    9161009    int rc;
     
    9321025    uint32_t aResBHS[12];
    9331026    char *pszNext;
     1027    PISCSIIMAGE pImage = (PISCSIIMAGE)pvUser;
    9341028
    9351029    bool fParameterNeg = true;;
     
    9661060
    9671061restart:
    968     if (pImage->Socket == NIL_RTSOCKET)
     1062    if (!iscsiIsClientConnected(pImage))
    9691063    {
    9701064        rc = iscsiTransportOpen(pImage);
     
    11101204            cnISCSIRes++;
    11111205
    1112             rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes);
     1206            rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes, true);
    11131207            if (RT_FAILURE(rc))
    11141208                break;
     
    13511445 * @param   pImage      The iSCSI connection state to be used.
    13521446 */
    1353 static int iscsiDetach(PISCSIIMAGE pImage)
     1447static int iscsiDetach(void *pvUser)
    13541448{
    13551449    int rc;
     
    13581452    ISCSIREQ aISCSIReq[4];
    13591453    uint32_t aReqBHS[12];
     1454    PISCSIIMAGE pImage = (PISCSIIMAGE)pvUser;
     1455
    13601456    LogFlowFunc(("entering\n"));
    13611457
     
    13991495            aISCSIRes.pvSeg = aResBHS;
    14001496            aISCSIRes.cbSeg = sizeof(aResBHS);
    1401             rc = iscsiRecvPDU(pImage, itt, &aISCSIRes, 1);
     1497            rc = iscsiRecvPDU(pImage, itt, &aISCSIRes, 1, true);
    14021498            if (RT_SUCCESS(rc))
    14031499            {
     
    15571653        cnISCSIRes++;
    15581654
    1559         rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes);
     1655        rc = iscsiRecvPDU(pImage, itt, aISCSIRes, cnISCSIRes, true);
    15601656        if (RT_FAILURE(rc))
    15611657            break;
     
    17361832 * @param   cnRes       Number of valid iSCSI response sections in the array.
    17371833 */
    1738 static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes)
     1834static int iscsiRecvPDU(PISCSIIMAGE pImage, uint32_t itt, PISCSIRES paRes, uint32_t cnRes, bool fSelect)
    17391835{
    17401836    int rc = VINF_SUCCESS;
     
    17451841        aResBuf.pvSeg = pImage->pvRecvPDUBuf;
    17461842        aResBuf.cbSeg = pImage->cbRecvPDUBuf;
    1747         rc = iscsiTransportRead(pImage, &aResBuf, 1);
     1843        rc = iscsiTransportRead(pImage, &aResBuf, 1, fSelect);
    17481844        if (RT_FAILURE(rc))
    17491845        {
     
    18281924            }
    18291925            /* Finally check whether the received PDU matches what the caller wants. */
    1830             if (itt == pcvResSeg[4])
     1926            if (   itt == pcvResSeg[4]
     1927                && itt != ISCSI_TASK_TAG_RSVD)
    18311928            {
    18321929                /* Copy received PDU (one segment) to caller-provided buffers. */
     
    18881985
    18891986                iscsiSendPDU(pImage, aISCSIReq, cnISCSIReq, ISCSIPDU_NO_REATTACH);
     1987                /* Break if the caller wanted to process the NOP-in only. */
     1988                if (itt == ISCSI_TASK_TAG_RSVD)
     1989                    break;
    18901990            }
    18911991        }
     
    22712371
    22722372/**
     2373 * Internal. - Wrapper around the extended select callback of the net interface.
     2374 */
     2375DECLINLINE(int) iscsiIoThreadWait(PISCSIIMAGE pImage, RTMSINTERVAL cMillies, uint32_t *pfEvents)
     2376{
     2377    return pImage->pInterfaceNetCallbacks->pfnSelectOneEx(pImage->Socket, pfEvents, cMillies);
     2378}
     2379
     2380/**
     2381 * Internal. - Pokes a thread waiting for I/O.
     2382 */
     2383DECLINLINE(int) iscsiIoThreadPoke(PISCSIIMAGE pImage)
     2384{
     2385    return pImage->pInterfaceNetCallbacks->pfnPoke(pImage->Socket);
     2386}
     2387
     2388/**
     2389 * Internal. - Get the next request from the queue.
     2390 */
     2391DECLINLINE(PISCSICMD) iscsiCmdGet(PISCSIIMAGE pImage)
     2392{
     2393    int rc;
     2394    PISCSICMD pIScsiCmd = NULL;
     2395
     2396    rc = RTSemMutexRequest(pImage->MutexReqQueue, RT_INDEFINITE_WAIT);
     2397    AssertRC(rc);
     2398
     2399    pIScsiCmd = pImage->pScsiReqQueue;
     2400    if (pIScsiCmd)
     2401    {
     2402        pImage->pScsiReqQueue = pIScsiCmd->pNext;
     2403        pIScsiCmd->pNext = NULL;
     2404    }
     2405
     2406    rc = RTSemMutexRelease(pImage->MutexReqQueue);
     2407    AssertRC(rc);
     2408
     2409    return pIScsiCmd;
     2410}
     2411
     2412
     2413/**
     2414 * Internal. - Adds the given command to the queue.
     2415 */
     2416DECLINLINE(int) iscsiCmdPut(PISCSIIMAGE pImage, PISCSICMD pIScsiCmd)
     2417{
     2418    int rc = RTSemMutexRequest(pImage->MutexReqQueue, RT_INDEFINITE_WAIT);
     2419    AssertRC(rc);
     2420
     2421    pIScsiCmd->pNext = pImage->pScsiReqQueue;
     2422    pImage->pScsiReqQueue = pIScsiCmd;
     2423
     2424    rc = RTSemMutexRelease(pImage->MutexReqQueue);
     2425    AssertRC(rc);
     2426
     2427    iscsiIoThreadPoke(pImage);
     2428
     2429    /* Wait if the request is synchronous. */
     2430    if (pIScsiCmd->fSync)
     2431    {
     2432        rc = RTSemEventWait(pIScsiCmd->Type.Sync.EventSem, RT_INDEFINITE_WAIT);
     2433        AssertRC(rc);
     2434        rc = pIScsiCmd->Type.Sync.rcCmd;
     2435    }
     2436    else
     2437        rc = VINF_SUCCESS;
     2438
     2439    return rc;
     2440}
     2441
     2442/**
     2443 * Internal. - Completes the request with the appropriate action.
     2444 *             Synchronous requests are completed with waking up the thread
     2445 *             and asynchronous ones by continuing the associated I/O context.
     2446 */
     2447static void iscsiCmdComplete(PISCSICMD pIScsiCmd, int rcCmd)
     2448{
     2449    if (pIScsiCmd->fSync)
     2450    {
     2451        int rc;
     2452
     2453        /* Store completion code */
     2454        pIScsiCmd->Type.Sync.rcCmd = rcCmd;
     2455
     2456        /*
     2457         * Wakeup the waiting thread. We are NOT allowed to touch the request
     2458         * beyond this call.
     2459         */
     2460        rc = RTSemEventSignal(pIScsiCmd->Type.Sync.EventSem);
     2461        AssertRC(rc);
     2462    }
     2463    else
     2464        AssertMsgFailed(("Not implemented yet\n"));
     2465}
     2466
     2467/**
     2468 * Internal. Main iSCSI I/O worker.
     2469 */
     2470static DECLCALLBACK(int) iscsiIoThreadWorker(RTTHREAD ThreadSelf, void *pvUser)
     2471{
     2472    PISCSIIMAGE pImage = (PISCSIIMAGE)pvUser;
     2473
     2474    while (pImage->fRunning)
     2475    {
     2476        uint32_t fEvents = 0;
     2477        int rc;
     2478
     2479        /* Wait for work or for data from the target. */
     2480        rc = iscsiIoThreadWait(pImage, RT_INDEFINITE_WAIT, &fEvents);
     2481        if (rc == VERR_INTERRUPTED)
     2482        {
     2483            /* Check the queue. */
     2484            PISCSICMD pIScsiCmd = iscsiCmdGet(pImage);
     2485
     2486            while (pIScsiCmd)
     2487            {
     2488                switch (pIScsiCmd->enmCmdType)
     2489                {
     2490                    case ISCSICMDTYPE_REQ:
     2491                    {
     2492                        rc = iscsiCommand(pImage, pIScsiCmd->CmdType.ScsiReq.pScsiReq);
     2493                        break;
     2494                    }
     2495                    case ISCSICMDTYPE_EXEC:
     2496                    {
     2497                        rc = pIScsiCmd->CmdType.Exec.pfnExec(pIScsiCmd->CmdType.Exec.pvUser);
     2498                        break;
     2499                    }
     2500                    default:
     2501                        AssertMsgFailed(("Invalid command type %d\n", pIScsiCmd->enmCmdType));
     2502                }
     2503
     2504                iscsiCmdComplete(pIScsiCmd, rc);
     2505                pIScsiCmd = iscsiCmdGet(pImage);
     2506            }
     2507        }
     2508        else if (RT_SUCCESS(rc))
     2509        {
     2510            /*
     2511             * There is data on the socket.
     2512             *
     2513             * @todo: This will only handle NOP-IN requests. Check other requests.
     2514             */
     2515            if (fEvents & VD_INTERFACETCPNET_EVT_READ)
     2516            {
     2517                rc = iscsiRecvPDU(pImage, ISCSI_TASK_TAG_RSVD, NULL, 0, false);
     2518                if (RT_FAILURE(rc))
     2519                    LogRel(("iSCSI: Handling incoming request failed %Rrc\n", rc));
     2520            }
     2521            else
     2522                LogRel(("iSCSI: Received unexpected event %#x\n", fEvents));
     2523        }
     2524        else
     2525        {
     2526            LogRel(("iSCSI: Waiting for I/O failed rc=%Rrc\n", rc));
     2527        }
     2528    }
     2529
     2530    return VINF_SUCCESS;
     2531}
     2532
     2533/**
     2534 * Internal. - Enqueues a request in a synchronous fashion
     2535 * i.e. returns when the request completed.
     2536 */
     2537static int iscsiCommandSync(PISCSIIMAGE pImage, PSCSIREQ pScsiReq, bool fRetry, int rcSense)
     2538{
     2539    int rc;
     2540
     2541    if (pImage->fExtendedSelectSupported)
     2542    {
     2543        ISCSICMD IScsiCmd;
     2544
     2545        /* Init the command structure. */
     2546        IScsiCmd.pNext                    = NULL;
     2547        IScsiCmd.enmCmdType               = ISCSICMDTYPE_REQ;
     2548        IScsiCmd.fSync                    = true;
     2549        IScsiCmd.Type.Sync.rcCmd          = VINF_SUCCESS;
     2550        IScsiCmd.CmdType.ScsiReq.pScsiReq = pScsiReq;
     2551
     2552        /* Create event semaphore. */
     2553        rc = RTSemEventCreate(&IScsiCmd.Type.Sync.EventSem);
     2554        if (RT_FAILURE(rc))
     2555            return rc;
     2556
     2557        if (fRetry)
     2558        {
     2559            for (unsigned i = 0; i < 10; i++)
     2560            {
     2561                rc = iscsiCmdPut(pImage, &IScsiCmd);
     2562                if (    (RT_SUCCESS(rc) && !pScsiReq->cbSense)
     2563                    ||  RT_FAILURE(rc))
     2564                    break;
     2565                rc = rcSense;
     2566            }
     2567        }
     2568        else
     2569        {
     2570            rc = iscsiCmdPut(pImage, &IScsiCmd);
     2571            if (RT_SUCCESS(rc) && pScsiReq->cbSense > 0)
     2572                rc = rcSense;
     2573        }
     2574
     2575        RTSemEventDestroy(IScsiCmd.Type.Sync.EventSem);
     2576    }
     2577    else
     2578    {
     2579        if (fRetry)
     2580        {
     2581            for (unsigned i = 0; i < 10; i++)
     2582            {
     2583                rc = iscsiCommand(pImage, pScsiReq);
     2584                if (    (RT_SUCCESS(rc) && !pScsiReq->cbSense)
     2585                    ||  RT_FAILURE(rc))
     2586                    break;
     2587                rc = rcSense;
     2588            }
     2589        }
     2590        else
     2591        {
     2592            rc = iscsiCommand(pImage, pScsiReq);
     2593            if (RT_SUCCESS(rc) && pScsiReq->cbSense > 0)
     2594                rc = rcSense;
     2595        }
     2596    }
     2597
     2598    return rc;
     2599}
     2600
     2601/**
     2602 * Internal. - Executes a given function in a synchronous fashion
     2603 *             on the I/O thread if available.
     2604 */
     2605static int iscsiExecSync(PISCSIIMAGE pImage, PFNISCSIEXEC pfnExec, void *pvUser)
     2606{
     2607    int rc;
     2608
     2609    if (pImage->fExtendedSelectSupported)
     2610    {
     2611        ISCSICMD IScsiCmd;
     2612
     2613        /* Init the command structure. */
     2614        IScsiCmd.pNext                = NULL;
     2615        IScsiCmd.enmCmdType           = ISCSICMDTYPE_EXEC;
     2616        IScsiCmd.fSync                = true;
     2617        IScsiCmd.Type.Sync.rcCmd      = VINF_SUCCESS;
     2618        IScsiCmd.CmdType.Exec.pfnExec = pfnExec;
     2619        IScsiCmd.CmdType.Exec.pvUser  = pvUser;
     2620
     2621        /* Create event semaphore. */
     2622        rc = RTSemEventCreate(&IScsiCmd.Type.Sync.EventSem);
     2623        if (RT_FAILURE(rc))
     2624            return rc;
     2625
     2626        rc = iscsiCmdPut(pImage, &IScsiCmd);
     2627        RTSemEventDestroy(IScsiCmd.Type.Sync.EventSem);
     2628    }
     2629    else
     2630    {
     2631        /* No I/O thread, execute in the current thread. */
     2632        rc = pfnExec(pvUser);
     2633    }
     2634
     2635    return rc;
     2636}
     2637
     2638/**
    22732639 * Internal. Free all allocated space for representing an image, and optionally
    22742640 * delete the image from disk.
     
    22832649        /* Detaching only makes sense when the mutex is there. Otherwise the
    22842650         * failure happened long before we could attach to the target. */
    2285         iscsiDetach(pImage);
     2651        iscsiExecSync(pImage, iscsiDetach, pImage);
    22862652        RTSemMutexDestroy(pImage->Mutex);
    22872653        pImage->Mutex = NIL_RTSEMMUTEX;
     2654    }
     2655    if (pImage->hThreadIo != NIL_RTTHREAD)
     2656    {
     2657        int rc;
     2658
     2659        ASMAtomicXchgBool(&pImage->fRunning, false);
     2660        rc = iscsiIoThreadPoke(pImage);
     2661        AssertRC(rc);
     2662
     2663        /* Wait for the thread to terminate. */
     2664        rc = RTThreadWait(pImage->hThreadIo, RT_INDEFINITE_WAIT, NULL);
     2665        AssertRC(rc);
     2666    }
     2667    /* Destroy the socket. */
     2668    if (pImage->Socket != NIL_VDSOCKET)
     2669    {
     2670        pImage->pInterfaceNetCallbacks->pfnSocketDestroy(pImage->Socket);
     2671    }
     2672    if (pImage->MutexReqQueue != NIL_RTSEMMUTEX)
     2673    {
     2674        RTSemMutexDestroy(pImage->MutexReqQueue);
     2675        pImage->MutexReqQueue = NIL_RTSEMMUTEX;
    22882676    }
    22892677    if (pImage->pszTargetName)
     
    23912779    }
    23922780    pImage->Mutex           = NIL_RTSEMMUTEX;
     2781    pImage->MutexReqQueue   = NIL_RTSEMMUTEX;
    23932782    rc = RTSemMutexCreate(&pImage->Mutex);
     2783    if (RT_FAILURE(rc))
     2784        goto out;
     2785
     2786    rc = RTSemMutexCreate(&pImage->MutexReqQueue);
    23942787    if (RT_FAILURE(rc))
    23952788        goto out;
     
    25342927    pImage->pszHostname    = NULL;
    25352928    pImage->uPort          = 0;
    2536     pImage->Socket         = NIL_RTSOCKET;
     2929    pImage->Socket         = NIL_VDSOCKET;
    25372930    /* Query the iSCSI lower level configuration. */
    25382931    rc = VDCFGQueryU32Def(pImage->pInterfaceConfigCallbacks,
     
    25652958    }
    25662959
     2960    /* Create the socket structure. */
     2961    rc = pImage->pInterfaceNetCallbacks->pfnSocketCreate(VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT,
     2962                                                         &pImage->Socket);
     2963    if (RT_SUCCESS(rc))
     2964    {
     2965        pImage->fExtendedSelectSupported = true;
     2966        pImage->fRunning = true;
     2967        rc = RTThreadCreate(&pImage->hThreadIo, iscsiIoThreadWorker, pImage, 0,
     2968                            RTTHREADTYPE_IO, RTTHREADFLAGS_WAITABLE, "iSCSI-Io");
     2969        if (RT_FAILURE(rc))
     2970        {
     2971            LogFunc(("Creating iSCSI I/O thread failed rc=%Rrc\n", rc));
     2972            goto out;
     2973        }
     2974    }
     2975    else if (rc == VERR_NOT_SUPPORTED)
     2976    {
     2977        /* Async I/O is not supported without extended select. */
     2978        if ((uOpenFlags & VD_OPEN_FLAGS_ASYNC_IO))
     2979        {
     2980            LogFunc(("Extended select is not supported by the interface but async I/O is requested -> %Rrc\n", rc));
     2981            goto out;
     2982        }
     2983        else
     2984        {
     2985            pImage->fExtendedSelectSupported = false;
     2986            rc = pImage->pInterfaceNetCallbacks->pfnSocketCreate(0, &pImage->Socket);
     2987            if (RT_FAILURE(rc))
     2988            {
     2989                LogFunc(("Creating socket failed -> %Rrc\n", rc));
     2990                goto out;
     2991            }
     2992        }
     2993    }
     2994    else
     2995    {
     2996        LogFunc(("Creating socket failed -> %Rrc\n", rc));
     2997        goto out;
     2998    }
     2999
    25673000    /*
    25683001     * Attach to the iSCSI target. This implicitly establishes the iSCSI
    25693002     * transport connection.
    25703003     */
    2571     rc = iscsiAttach(pImage);
    2572 
     3004    rc = iscsiExecSync(pImage, iscsiAttach, pImage);
    25733005    if (RT_FAILURE(rc))
    25743006    {
     
    26113043    sr.pvSense = sense;
    26123044
    2613     rc = iscsiCommand(pImage, &sr);
     3045    rc = iscsiCommandSync(pImage, &sr, false, VERR_INVALID_STATE);
    26143046    if (RT_FAILURE(rc))
    26153047    {
     
    26393071    sr.pvSense = sense;
    26403072
    2641     for (unsigned i = 0; i < 10; i++)
    2642     {
    2643         rc = iscsiCommand(pImage, &sr);
    2644         if (    (RT_SUCCESS(rc) && !sr.cbSense)
    2645             ||  RT_FAILURE(rc))
    2646             break;
    2647         rc = VERR_INVALID_STATE;
    2648     }
     3073    rc = iscsiCommandSync(pImage, &sr, true /* fRetry */, VERR_INVALID_STATE);
    26493074    if (RT_SUCCESS(rc))
    26503075    {
     
    26903115    sr.pvSense = sense;
    26913116
    2692     for (unsigned i = 0; i < 10; i++)
    2693     {
    2694         rc = iscsiCommand(pImage, &sr);
    2695         if (    (RT_SUCCESS(rc) && !sr.cbSense)
    2696             ||  RT_FAILURE(rc))
    2697             break;
    2698         rc = VERR_INVALID_STATE;
    2699     }
     3117    rc = iscsiCommandSync(pImage, &sr, true /* fRetry */, VERR_INVALID_STATE);
    27003118    if (RT_SUCCESS(rc))
    27013119    {
     
    27053123            goto out;
    27063124        }
    2707    }
     3125    }
    27083126    else
    27093127    {
     
    27333151    sr.pvSense = sense;
    27343152
    2735     rc = iscsiCommand(pImage, &sr);
     3153    rc = iscsiCommandSync(pImage, &sr, false /* fRetry */, VINF_SUCCESS);
    27363154    if (   RT_SUCCESS(rc)
    27373155        && sr.status == SCSI_STATUS_OK)
     
    27753193        sr.pvSense = sense;
    27763194
    2777         rc = iscsiCommand(pImage, &sr);
     3195        rc = iscsiCommandSync(pImage, &sr, false /* fRetry */, VINF_SUCCESS);
    27783196        if (RT_SUCCESS(rc))
    27793197        {
     
    28233241    sr.cbSense = sizeof(sense);
    28243242    sr.pvSense = sense;
    2825     rc = iscsiCommand(pImage, &sr);
     3243    rc = iscsiCommandSync(pImage, &sr, false /* fRetry */, VINF_SUCCESS);
    28263244    if (   RT_SUCCESS(rc)
    28273245        && (sr.status == SCSI_STATUS_OK)
     
    28633281            sr.pvSense = sense;
    28643282            sr.status  = 0;
    2865             rc = iscsiCommand(pImage, &sr);
     3283            rc = iscsiCommandSync(pImage, &sr, false /* fRetry */, VINF_SUCCESS);
    28663284            if (   RT_SUCCESS(rc)
    28673285                && (sr.status == SCSI_STATUS_OK))
     
    28873305    }
    28883306
    2889 
    28903307out:
    28913308    if (RT_FAILURE(rc))
     
    30743491    sr.pvSense = sense;
    30753492
    3076     for (unsigned i = 0; i < 10; i++)
    3077     {
    3078         rc = iscsiCommand(pImage, &sr);
    3079         if (    (RT_SUCCESS(rc) && !sr.cbSense)
    3080             ||  RT_FAILURE(rc))
    3081             break;
    3082         rc = VERR_READ_ERROR;
    3083     }
     3493    rc = iscsiCommandSync(pImage, &sr, true, VERR_READ_ERROR);
    30843494    if (RT_FAILURE(rc))
    30853495    {
     
    31553565    sr.pvSense = sense;
    31563566
    3157     for (unsigned i = 0; i < 10; i++)
    3158     {
    3159         rc = iscsiCommand(pImage, &sr);
    3160         if (    (RT_SUCCESS(rc) && !sr.cbSense)
    3161             ||  RT_FAILURE(rc))
    3162             break;
    3163         rc = VERR_WRITE_ERROR;
    3164     }
     3567    rc = iscsiCommandSync(pImage, &sr, true, VERR_WRITE_ERROR);
    31653568    if (RT_FAILURE(rc))
    31663569    {
     
    32113614    sr.pvSense = sense;
    32123615
    3213     rc = iscsiCommand(pImage, &sr);
     3616    rc = iscsiCommandSync(pImage, &sr, false, VINF_SUCCESS);
    32143617    if (RT_FAILURE(rc))
    32153618        AssertMsgFailed(("iscsiCommand(%s) -> %Rrc\n", pImage->pszTargetName, rc));
  • trunk/src/VBox/Main/MediumImpl.cpp

    r31068 r31098  
    169169};
    170170
     171typedef struct VDSOCKETINT
     172{
     173    /** Socket handle. */
     174    RTSOCKET hSocket;
     175} VDSOCKETINT, *PVDSOCKETINT;
     176
    171177////////////////////////////////////////////////////////////////////////////////
    172178//
     
    672678    m->vdIfCallsTcpNet.cbSize = sizeof(VDINTERFACETCPNET);
    673679    m->vdIfCallsTcpNet.enmInterface = VDINTERFACETYPE_TCPNET;
    674     m->vdIfCallsTcpNet.pfnClientConnect = RTTcpClientConnect;
    675     m->vdIfCallsTcpNet.pfnClientClose = RTTcpClientClose;
    676     m->vdIfCallsTcpNet.pfnSelectOne = RTTcpSelectOne;
    677     m->vdIfCallsTcpNet.pfnRead = RTTcpRead;
    678     m->vdIfCallsTcpNet.pfnWrite = RTTcpWrite;
    679     m->vdIfCallsTcpNet.pfnSgWrite = RTTcpSgWrite;
    680     m->vdIfCallsTcpNet.pfnFlush = RTTcpFlush;
    681     m->vdIfCallsTcpNet.pfnSetSendCoalescing = RTTcpSetSendCoalescing;
    682     m->vdIfCallsTcpNet.pfnGetLocalAddress = RTTcpGetLocalAddress;
    683     m->vdIfCallsTcpNet.pfnGetPeerAddress = RTTcpGetPeerAddress;
     680    m->vdIfCallsTcpNet.pfnSocketCreate = vdTcpSocketCreate;
     681    m->vdIfCallsTcpNet.pfnSocketDestroy = vdTcpSocketDestroy;
     682    m->vdIfCallsTcpNet.pfnClientConnect = vdTcpClientConnect;
     683    m->vdIfCallsTcpNet.pfnClientClose = vdTcpClientClose;
     684    m->vdIfCallsTcpNet.pfnIsClientConnected = vdTcpIsClientConnected;
     685    m->vdIfCallsTcpNet.pfnSelectOne = vdTcpSelectOne;
     686    m->vdIfCallsTcpNet.pfnRead = vdTcpRead;
     687    m->vdIfCallsTcpNet.pfnWrite = vdTcpWrite;
     688    m->vdIfCallsTcpNet.pfnSgWrite = vdTcpSgWrite;
     689    m->vdIfCallsTcpNet.pfnFlush = vdTcpFlush;
     690    m->vdIfCallsTcpNet.pfnSetSendCoalescing = vdTcpSetSendCoalescing;
     691    m->vdIfCallsTcpNet.pfnGetLocalAddress = vdTcpGetLocalAddress;
     692    m->vdIfCallsTcpNet.pfnGetPeerAddress = vdTcpGetPeerAddress;
     693    m->vdIfCallsTcpNet.pfnSelectOneEx = NULL;
     694    m->vdIfCallsTcpNet.pfnPoke = NULL;
    684695
    685696    /* Initialize the per-disk interface chain */
     
    50515062}
    50525063
     5064DECLCALLBACK(int) Medium::vdTcpSocketCreate(uint32_t fFlags, PVDSOCKET pSock)
     5065{
     5066    PVDSOCKETINT pSocketInt = NULL;
     5067
     5068    if ((fFlags & VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT) != 0)
     5069        return VERR_NOT_SUPPORTED;
     5070
     5071    pSocketInt = (PVDSOCKETINT)RTMemAllocZ(sizeof(VDSOCKETINT));
     5072    if (!pSocketInt)
     5073        return VERR_NO_MEMORY;
     5074
     5075    pSocketInt->hSocket = NIL_RTSOCKET;
     5076    *pSock = pSocketInt;
     5077    return VINF_SUCCESS;
     5078}
     5079
     5080DECLCALLBACK(int) Medium::vdTcpSocketDestroy(VDSOCKET Sock)
     5081{
     5082    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5083
     5084    if (pSocketInt->hSocket != NIL_RTSOCKET)
     5085        RTTcpClientClose(pSocketInt->hSocket);
     5086
     5087    RTMemFree(pSocketInt);
     5088
     5089    return VINF_SUCCESS;
     5090}
     5091
     5092DECLCALLBACK(int) Medium::vdTcpClientConnect(VDSOCKET Sock, const char *pszAddress, uint32_t uPort)
     5093{
     5094    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5095
     5096    return RTTcpClientConnect(pszAddress, uPort, &pSocketInt->hSocket);
     5097}
     5098
     5099DECLCALLBACK(int) Medium::vdTcpClientClose(VDSOCKET Sock)
     5100{
     5101    int rc = VINF_SUCCESS;
     5102    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5103
     5104    rc = RTTcpClientClose(pSocketInt->hSocket);
     5105    pSocketInt->hSocket = NIL_RTSOCKET;
     5106    return rc;
     5107}
     5108
     5109DECLCALLBACK(bool) Medium::vdTcpIsClientConnected(VDSOCKET Sock)
     5110{
     5111    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5112    return pSocketInt->hSocket != NIL_RTSOCKET;
     5113}
     5114
     5115DECLCALLBACK(int) Medium::vdTcpSelectOne(VDSOCKET Sock, RTMSINTERVAL cMillies)
     5116{
     5117    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5118    return RTTcpSelectOne(pSocketInt->hSocket, cMillies);
     5119}
     5120
     5121DECLCALLBACK(int) Medium::vdTcpRead(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)
     5122{
     5123    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5124    return RTTcpRead(pSocketInt->hSocket, pvBuffer, cbBuffer, pcbRead);
     5125}
     5126
     5127DECLCALLBACK(int) Medium::vdTcpWrite(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer)
     5128{
     5129    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5130    return RTTcpWrite(pSocketInt->hSocket, pvBuffer, cbBuffer);
     5131}
     5132
     5133DECLCALLBACK(int) Medium::vdTcpSgWrite(VDSOCKET Sock, PCRTSGBUF pSgBuf)
     5134{
     5135    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5136    return RTTcpSgWrite(pSocketInt->hSocket, pSgBuf);
     5137}
     5138
     5139DECLCALLBACK(int) Medium::vdTcpFlush(VDSOCKET Sock)
     5140{
     5141    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5142    return RTTcpFlush(pSocketInt->hSocket);
     5143}
     5144
     5145DECLCALLBACK(int) Medium::vdTcpSetSendCoalescing(VDSOCKET Sock, bool fEnable)
     5146{
     5147    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5148    return RTTcpSetSendCoalescing(pSocketInt->hSocket, fEnable);
     5149}
     5150
     5151DECLCALLBACK(int) Medium::vdTcpGetLocalAddress(VDSOCKET Sock, PRTNETADDR pAddr)
     5152{
     5153    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5154    return RTTcpGetLocalAddress(pSocketInt->hSocket, pAddr);
     5155}
     5156
     5157DECLCALLBACK(int) Medium::vdTcpGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr)
     5158{
     5159    PVDSOCKETINT pSocketInt = (PVDSOCKETINT)Sock;
     5160    return RTTcpGetPeerAddress(pSocketInt->hSocket, pAddr);
     5161}
     5162
     5163
    50535164/**
    50545165 * Starts a new thread driven by the appropriate Medium::Task::handler() method.
  • trunk/src/VBox/Main/include/MediumImpl.h

    r31063 r31098  
    2020#ifndef ____H_MEDIUMIMPL
    2121#define ____H_MEDIUMIMPL
     22
     23#include <VBox/VBoxHDD.h>
    2224
    2325#include "VirtualBoxBase.h"
     
    255257                                           char *pszValue, size_t cchValue);
    256258
     259    static DECLCALLBACK(int) vdTcpSocketCreate(uint32_t fFlags, PVDSOCKET pSock);
     260    static DECLCALLBACK(int) vdTcpSocketDestroy(VDSOCKET Sock);
     261    static DECLCALLBACK(int) vdTcpClientConnect(VDSOCKET Sock, const char *pszAddress, uint32_t uPort);
     262    static DECLCALLBACK(int) vdTcpClientClose(VDSOCKET Sock);
     263    static DECLCALLBACK(bool) vdTcpIsClientConnected(VDSOCKET Sock);
     264    static DECLCALLBACK(int) vdTcpSelectOne(VDSOCKET Sock, RTMSINTERVAL cMillies);
     265    static DECLCALLBACK(int) vdTcpRead(VDSOCKET Sock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead);
     266    static DECLCALLBACK(int) vdTcpWrite(VDSOCKET Sock, const void *pvBuffer, size_t cbBuffer);
     267    static DECLCALLBACK(int) vdTcpSgWrite(VDSOCKET Sock, PCRTSGBUF pSgBuf);
     268    static DECLCALLBACK(int) vdTcpFlush(VDSOCKET Sock);
     269    static DECLCALLBACK(int) vdTcpSetSendCoalescing(VDSOCKET Sock, bool fEnable);
     270    static DECLCALLBACK(int) vdTcpGetLocalAddress(VDSOCKET Sock, PRTNETADDR pAddr);
     271    static DECLCALLBACK(int) vdTcpGetPeerAddress(VDSOCKET Sock, PRTNETADDR pAddr);
     272
    257273    class Task;
    258274    class CreateBaseTask;
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