VirtualBox

Ignore:
Timestamp:
Jul 4, 2023 4:23:18 PM (20 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
158104
Message:

Shared Clipboard: More work on making the internal APIs more fine grained and easier to follow. bugref:9437

Location:
trunk/src/VBox/HostServices/SharedClipboard
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h

    r100205 r100367  
    282282extern SHCLEXTSTATE g_ExtState;
    283283
    284 int shClSvcSetSource(PSHCLCLIENT pClient, SHCLSOURCE enmSource);
    285 
    286284void shClSvcMsgQueueReset(PSHCLCLIENT pClient);
    287285PSHCLCLIENTMSG shClSvcMsgAlloc(PSHCLCLIENT pClient, uint32_t uMsg, uint32_t cParms);
     
    302300int shClSvcClientWakeup(PSHCLCLIENT pClient);
    303301
    304 # ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    305 int shClSvcTransferModeSet(uint32_t fMode);
    306 int shClSvcTransferInit(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, PSHCLTRANSFER *ppTransfer);
    307 int shClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
    308 int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest);
    309 bool shClSvcTransferMsgIsAllowed(uint32_t uMode, uint32_t uMsg);
    310 void shClSvcClientTransfersReset(PSHCLCLIENT pClient);
    311 #endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    312 
    313302/** @name Service functions, accessible by the backends.
    314303 * Locking is between the (host) service thread and the platform-dependent (window) thread.
     
    316305 */
    317306int ShClSvcReadDataFromGuestAsync(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent);
     307int ShClSvcReadDataFromGuest(PSHCLCLIENT pClient, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb);
    318308int ShClSvcGuestDataSignal(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData);
    319309int ShClSvcHostReportFormats(PSHCLCLIENT pClient, SHCLFORMATS fFormats);
     
    451441 */
    452442/**
    453  * Called after a transfer got created.
     443 * Called before a transfer gets destroyed.
    454444 *
    455445 * @returns VBox status code.
    456446 * @param   pBackend            Shared Clipboard backend to use.
    457447 * @param   pClient             Shared Clipboard client context.
    458  * @param   pTransfer           Shared Clipboard transfer created.
    459  */
    460 int ShClBackendTransferCreate(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
    461 /**
    462  * Called before a transfer gets destroyed.
     448 * @param   pTransfer           Shared Clipboard transfer to destroy.
     449 */
     450int ShClBackendTransferDestroy(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
     451/**
     452 * Called after a transfer status got processed.
    463453 *
    464454 * @returns VBox status code.
    465455 * @param   pBackend            Shared Clipboard backend to use.
    466456 * @param   pClient             Shared Clipboard client context.
    467  * @param   pTransfer           Shared Clipboard transfer to destroy.
    468  */
    469 int ShClBackendTransferDestroy(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
    470 /**
    471  * Called when getting (determining) the transfer roots on the host side.
     457 * @param   pTransfer           Shared Clipboard transfer to process status for.
     458 * @param   enmSource           Transfer source which issues the reply.
     459 * @param   enmStatus           Transfer status.
     460 * @param   rcStatus            Status code (IPRT-style). Depends on \a enmStatus set.
     461 */
     462int ShClBackendTransferHandleStatusReply(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLSOURCE enmSource, SHCLTRANSFERSTATUS enmStatus, int rcStatus);
     463/**
     464 * Called when the guest wants to read the transfer roots.
    472465 *
    473466 * @returns VBox status code.
     
    476469 * @param   pTransfer           Shared Clipboard transfer to get roots for.
    477470 */
    478 int ShClBackendTransferGetRoots(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
     471int ShClBackendTransferHGRootListRead(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
    479472/** @} */
    480473#endif
     
    497490
    498491int shClSvcTransferIfaceRootsGet(PSHCLTXPROVIDERCTX pCtx, PSHCLLIST pRootList);
    499 int shClSvcTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList);
    500 int shClSvcTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList);
    501 int shClSvcTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr);
    502 int shClSvcTransferIfaceListHdrWrite(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr);
    503 int shClSvcTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry);
    504 int shClSvcTransferIfaceListEntryWrite(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry);
    505 
    506 int shClSvcTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
     492int shClSvcTransferIfaceGHListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList);
     493int shClSvcTransferIfaceGHListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList);
     494int shClSvcTransferIfaceGHListHdrRead(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr);
     495int shClSvcTransferIfaceHGListHdrWrite(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr);
     496int shClSvcTransferIfaceGHListEntryRead(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry);
     497int shClSvcTransferIfaceHGListEntryWrite(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry);
     498
     499int shClSvcTransferIfaceGHObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
    507500                                PSHCLOBJHANDLE phObj);
    508 int shClSvcTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj);
    509 int shClSvcTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
     501int shClSvcTransferIfaceGHObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj);
     502int shClSvcTransferIfaceGHObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
    510503                                void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead);
    511 int shClSvcTransferIfaceObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
     504int shClSvcTransferIfaceHGObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
    512505                                 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten);
    513506/** @} */
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.cpp

    r100291 r100367  
    6161*   Prototypes                                                                                                                   *
    6262*********************************************************************************************************************************/
    63 static int shClSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
    64                                       uint64_t idCtx, PSHCLLISTOPENPARMS pOpenParms);
    65 static int shClSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM aParms[],
    66                                        uint64_t idCtx, SHCLLISTHANDLE hList);
    67 
    68 
    69 /*********************************************************************************************************************************
    70 *   Provider implementation                                                                                                      *
    71 *********************************************************************************************************************************/
    72 
    73 /**
    74  * Resets all transfers of a Shared Clipboard client.
    75  *
    76  * @param   pClient             Client to reset transfers for.
    77  */
    78 void shClSvcClientTransfersReset(PSHCLCLIENT pClient)
     63static int shClSvcTransferSendStatusAsyncInternal(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus, int rcTransfer, PSHCLEVENT *ppEvent);
     64static int shClSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM aParms[], uint64_t idCtx, PSHCLLISTOPENPARMS pOpenParms);
     65static int shClSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM aParms[], uint64_t idCtx, SHCLLISTHANDLE hList);
     66
     67
     68/**
     69 * Destroys all transfers of a Shared Clipboard client.
     70 *
     71 * @param   pClient             Client to destroy transfers for.
     72 */
     73void shClSvcTransferDestroyAll(PSHCLCLIENT pClient)
    7974{
    8075    if (!pClient)
     
    8378    LogFlowFuncEnter();
    8479
    85     /* Make sure to let the backend know that all transfers are getting destroyed. */
     80    /* Unregister and destroy all transfers.
     81     * Also make sure to let the backend know that all transfers are getting destroyed. */
    8682    uint32_t      uIdx = 0;
    8783    PSHCLTRANSFER pTransfer;
    8884    while ((pTransfer = ShClTransferCtxGetTransferByIndex(&pClient->Transfers.Ctx, uIdx++)))
    89         ShClBackendTransferDestroy(pClient->pBackend, pClient, pTransfer);
    90 
    91     ShClTransferCtxDestroy(&pClient->Transfers.Ctx);
     85        ShClSvcTransferDestroy(pClient, pTransfer);
     86}
     87
     88/**
     89 * Reads a root list header from the guest, asynchronous version.
     90 *
     91 * @returns VBox status code.
     92 * @param   pClient             Client to read from.
     93 * @param   idTransfer          Transfer ID to read root list header for.
     94 * @param   ppEvent             Where to return the event to wait for.
     95 *                              Must be released by the caller with ShClEventRelease().
     96 */
     97int ShClSvcTransferGHRootListReadHdrAsync(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer, PSHCLEVENT *ppEvent)
     98{
     99    LogFlowFuncEnter();
     100
     101    int rc;
     102
     103    PSHCLCLIENTMSG pMsgHdr = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ,
     104                                             VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
     105    if (pMsgHdr)
     106    {
     107        PSHCLEVENT pEvent;
     108        rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
     109        if (RT_SUCCESS(rc))
     110        {
     111            HGCMSvcSetU64(&pMsgHdr->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
     112                                                                        idTransfer, pEvent->idEvent));
     113            HGCMSvcSetU32(&pMsgHdr->aParms[1], 0 /* fRoots */);
     114
     115            shClSvcClientLock(pClient);
     116
     117            shClSvcMsgAdd(pClient, pMsgHdr, true /* fAppend */);
     118            rc = shClSvcClientWakeup(pClient);
     119
     120            shClSvcClientUnlock(pClient);
     121
     122            /* Remove event from list if caller did not request event handle or in case
     123             * of failure (in this case caller should not release event). */
     124            if (   RT_FAILURE(rc)
     125                || !ppEvent)
     126            {
     127                ShClEventRelease(pEvent);
     128                pEvent = NULL;
     129            }
     130            else if (ppEvent)
     131                *ppEvent = pEvent;
     132        }
     133        else
     134        {
     135            shClSvcMsgFree(pClient, pMsgHdr);
     136            rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     137        }
     138    }
     139    else
     140        rc = VERR_NO_MEMORY;
     141
     142    LogFlowFuncLeaveRC(rc);
     143    return rc;
     144}
     145
     146/**
     147 * Reads a root list header from the guest.
     148 *
     149 * @returns VBox status code.
     150 * @param   pClient             Client to read from.
     151 * @param   idTransfer          Transfer ID to read root list header for.
     152 * @param   pHdr                Where to store the root list header on succeess.
     153 */
     154int ShClSvcTransferGHRootListReadHdr(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer, PSHCLLISTHDR pHdr)
     155{
     156    PSHCLEVENT pEvent;
     157    int rc = ShClSvcTransferGHRootListReadHdrAsync(pClient, idTransfer, &pEvent);
     158    if (RT_SUCCESS(rc))
     159    {
     160        PSHCLEVENTPAYLOAD pPayload;
     161        rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     162        if (RT_SUCCESS(rc))
     163        {
     164            Assert(pPayload->cbData == sizeof(SHCLLISTHDR));
     165
     166            memcpy(pHdr, (PSHCLLISTHDR)pPayload->pvData, sizeof(SHCLLISTHDR));
     167
     168            LogFlowFunc(("cRoots=%RU32, fFeatures=0x%x\n", pHdr->cEntries, pHdr->fFeatures));
     169
     170            ShClPayloadFree(pPayload);
     171        }
     172
     173        ShClEventRelease(pEvent);
     174        pEvent = NULL;
     175    }
     176
     177    LogFlowFuncLeaveRC(rc);
     178    return rc;
     179}
     180
     181/**
     182 * Reads a root list entry from the guest, asynchronous version.
     183 *
     184 * @returns VBox status code.
     185 * @param   pClient             Client to read from.
     186 * @param   idTransfer          Transfer ID to read root list header for.
     187 * @param   idxEntry            Index of entry to read.
     188 * @param   ppEvent             Where to return the event to wait for.
     189 *                              Must be released by the caller with ShClEventRelease().
     190 */
     191int ShClSvcTransferGHRootListReadEntryAsync(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer, uint64_t idxEntry,
     192                                            PSHCLEVENT *ppEvent)
     193{
     194    LogFlowFuncEnter();
     195
     196    PSHCLCLIENTMSG pMsgEntry = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
     197                                               VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
     198
     199    PSHCLEVENT pEvent;
     200    int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
     201    if (RT_SUCCESS(rc))
     202    {
     203        HGCMSvcSetU64(&pMsgEntry->aParms[0],
     204                      VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uClientID, idTransfer, pEvent->idEvent));
     205        HGCMSvcSetU32(&pMsgEntry->aParms[1], 0 /* fFeatures */);
     206        HGCMSvcSetU64(&pMsgEntry->aParms[2], idxEntry /* uIndex */);
     207
     208        shClSvcClientLock(pClient);
     209
     210        shClSvcMsgAdd(pClient, pMsgEntry, true /* fAppend */);
     211        rc = shClSvcClientWakeup(pClient);
     212
     213        shClSvcClientUnlock(pClient);
     214
     215        /* Remove event from list if caller did not request event handle or in case
     216         * of failure (in this case caller should not release event). */
     217        if (   RT_FAILURE(rc)
     218            || !ppEvent)
     219        {
     220            ShClEventRelease(pEvent);
     221            pEvent = NULL;
     222        }
     223        else if (ppEvent)
     224            *ppEvent = pEvent;
     225    }
     226    else
     227        rc = VERR_NO_MEMORY;
     228
     229    LogFlowFuncLeave();
     230    return rc;
     231}
     232
     233/**
     234 * Reads a root list entry from the guest.
     235 *
     236 * @returns VBox status code.
     237 * @param   pClient             Client to read from.
     238 * @param   idTransfer          Transfer ID to read root list header for.
     239 * @param   idxEntry            Index of entry to read.
     240 * @param   ppListEntry         Where to return the allocated root list entry.
     241 */
     242int ShClSvcTransferGHRootListReadEntry(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer, uint64_t idxEntry,
     243                                       PSHCLLISTENTRY *ppListEntry)
     244{
     245    AssertPtrReturn(ppListEntry, VERR_INVALID_POINTER);
     246
     247    PSHCLEVENT pEvent;
     248    int rc = ShClSvcTransferGHRootListReadEntryAsync(pClient, idTransfer, idxEntry, &pEvent);
     249    if (RT_SUCCESS(rc))
     250    {
     251        PSHCLEVENTPAYLOAD pPayload;
     252        rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     253        if (RT_SUCCESS(rc))
     254        {
     255            *ppListEntry = (PSHCLLISTENTRY)pPayload->pvData; /* ppLisEntry own pPayload-pvData now. */
     256
     257        }
     258
     259        ShClEventRelease(pEvent);
     260        pEvent = NULL;
     261    }
     262
     263    LogFlowFuncLeaveRC(rc);
     264    return rc;
    92265}
    93266
     
    98271
    99272/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
    100 DECLCALLBACK(int) shClSvcTransferIfaceRootListRead(PSHCLTXPROVIDERCTX pCtx)
     273DECLCALLBACK(int) shClSvcTransferIfaceGHRootListRead(PSHCLTXPROVIDERCTX pCtx)
    101274{
    102275    LogFlowFuncEnter();
     
    105278    AssertPtr(pClient);
    106279
    107     int rc;
    108 
    109     PSHCLCLIENTMSG pMsgHdr = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ,
    110                                              VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
    111     if (pMsgHdr)
    112     {
    113         PSHCLEVENT pEvent;
    114         rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
    115         if (RT_SUCCESS(rc))
    116         {
    117             HGCMSvcSetU64(&pMsgHdr->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
    118                                                                         pCtx->pTransfer->State.uID, pEvent->idEvent));
    119             HGCMSvcSetU32(&pMsgHdr->aParms[1], 0 /* fRoots */);
    120 
    121             shClSvcClientLock(pClient);
    122 
    123             shClSvcMsgAdd(pClient, pMsgHdr, true /* fAppend */);
    124             rc = shClSvcClientWakeup(pClient);
    125 
    126             shClSvcClientUnlock(pClient);
    127 
     280    SHCLTRANSFERID const idTransfer = ShClTransferGetID(pCtx->pTransfer);
     281
     282    SHCLLISTHDR Hdr;
     283    int rc = ShClSvcTransferGHRootListReadHdr(pClient, idTransfer, &Hdr);
     284    if (RT_SUCCESS(rc))
     285    {
     286        for (uint64_t i = 0; i < Hdr.cEntries; i++)
     287        {
     288            PSHCLLISTENTRY pEntry;
     289            rc = ShClSvcTransferGHRootListReadEntry(pClient, idTransfer, i, &pEntry);
    128290            if (RT_SUCCESS(rc))
    129             {
    130                 PSHCLEVENTPAYLOAD pPayloadHdr;
    131                 rc = ShClEventWait(pEvent, pCtx->pTransfer->uTimeoutMs, &pPayloadHdr);
    132                 if (RT_SUCCESS(rc))
    133                 {
    134                     PSHCLLISTHDR pRootListHdr = (PSHCLLISTHDR)pPayloadHdr->pvData;
    135                     Assert(pPayloadHdr->cbData == sizeof(SHCLLISTHDR));
    136 
    137                     LogFlowFunc(("cRoots=%RU32, fFeatures=0x%x\n", pRootListHdr->cEntries, pRootListHdr->fFeatures));
    138 
    139                     for (uint32_t i = 0; i < pRootListHdr->cEntries; i++)
    140                     {
    141                         PSHCLCLIENTMSG pMsgEntry = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
    142                                                                    VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
    143 
    144                         PSHCLEVENT pEventRootEntry;
    145                         rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEventRootEntry);
    146                         if (RT_SUCCESS(rc))
    147                         {
    148                             HGCMSvcSetU64(&pMsgEntry->aParms[0],
    149                                           VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uClientID,
    150                                                                    pCtx->pTransfer->State.uID, pEventRootEntry->idEvent));
    151                             HGCMSvcSetU32(&pMsgEntry->aParms[1], 0 /* fFeatures */);
    152                             HGCMSvcSetU32(&pMsgEntry->aParms[2], i /* uIndex */);
    153 
    154                             shClSvcClientLock(pClient);
    155                             shClSvcMsgAdd(pClient, pMsgEntry, true /* fAppend */);
    156                             shClSvcClientUnlock(pClient);
    157 
    158                             PSHCLEVENTPAYLOAD pPayloadEntry;
    159                             rc = ShClEventWait(pEventRootEntry, pCtx->pTransfer->uTimeoutMs, &pPayloadEntry);
    160                             if (RT_FAILURE(rc))
    161                                 break;
    162 
    163                             PSHCLLISTENTRY pRootListEntry = (PSHCLLISTENTRY)pPayloadEntry->pvData;
    164                             Assert(pPayloadEntry->cbData == sizeof(SHCLLISTENTRY));
    165 
    166                             rc = ShClTransferListAddEntry(&pCtx->pTransfer->lstRoots, pRootListEntry, true /* fAppend */);
    167                             if (RT_FAILURE(rc))
    168                                 ShClPayloadFree(pPayloadEntry);
    169                             /* else don't call ShClPayloadFree() here, as pRootList own the data now. */
    170                             pPayloadEntry = NULL;
    171 
    172                             ShClEventRelease(pEventRootEntry);
    173                             pEventRootEntry = NULL;
    174                         }
    175                         else
    176                         {
    177                             shClSvcMsgFree(pClient, pMsgEntry);
    178                             rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
    179                         }
    180 
    181                         if (RT_FAILURE(rc))
    182                             break;
    183                     }
    184 
    185                     ShClPayloadFree(pPayloadHdr);
    186                 }
    187             }
    188 
    189             ShClEventRelease(pEvent);
    190         }
    191         else
    192         {
    193             shClSvcMsgFree(pClient, pMsgHdr);
    194             rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
    195         }
    196     }
    197     else
    198         rc = VERR_NO_MEMORY;
     291                rc = ShClTransferListAddEntry(&pCtx->pTransfer->lstRoots, pEntry, true /* fAppend */);
     292
     293            if (RT_FAILURE(rc))
     294                break;
     295        }
     296    }
    199297
    200298    LogFlowFuncLeave();
     
    203301
    204302/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
    205 DECLCALLBACK(int) shClSvcTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx,
    206                                                PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)
     303DECLCALLBACK(int) shClSvcTransferIfaceGHListOpen(PSHCLTXPROVIDERCTX pCtx,
     304                                                 PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)
    207305{
    208306    LogFlowFuncEnter();
     
    245343                        AssertPtr(pReply);
    246344
    247                         Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN);
     345                        Assert(pReply->uType == VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN);
    248346
    249347                        LogFlowFunc(("hList=%RU64\n", pReply->u.ListOpen.uHandle));
     
    272370
    273371/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
    274 DECLCALLBACK(int) shClSvcTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
     372DECLCALLBACK(int) shClSvcTransferIfaceGHListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
    275373{
    276374    LogFlowFuncEnter();
     
    327425
    328426/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
    329 DECLCALLBACK(int) shClSvcTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx,
    330                                                   SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
     427DECLCALLBACK(int) shClSvcTransferIfaceGHListHdrRead(PSHCLTXPROVIDERCTX pCtx,
     428                                                    SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
    331429{
    332430    LogFlowFuncEnter();
     
    387485
    388486/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrWrite */
    389 DECLCALLBACK(int) shClSvcTransferIfaceListHdrWrite(PSHCLTXPROVIDERCTX pCtx,
    390                                                    SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
     487DECLCALLBACK(int) shClSvcTransferIfaceHGListHdrWrite(PSHCLTXPROVIDERCTX pCtx,
     488                                                     SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
    391489{
    392490    RT_NOREF(pCtx, hList, pListHdr);
     
    398496
    399497/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
    400 DECLCALLBACK(int) shClSvcTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx,
    401                                                     SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
     498DECLCALLBACK(int) shClSvcTransferIfaceGHListEntryRead(PSHCLTXPROVIDERCTX pCtx,
     499                                                      SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
    402500{
    403501    LogFlowFuncEnter();
     
    458556
    459557/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryWrite */
    460 DECLCALLBACK(int) shClSvcTransferIfaceListEntryWrite(PSHCLTXPROVIDERCTX pCtx,
    461                                                      SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
     558DECLCALLBACK(int) shClSvcTransferIfaceHGListEntryWrite(PSHCLTXPROVIDERCTX pCtx,
     559                                                       SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
    462560{
    463561    RT_NOREF(pCtx, hList, pListEntry);
     
    469567
    470568/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
    471 DECLCALLBACK(int) shClSvcTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
     569DECLCALLBACK(int) shClSvcTransferIfaceGHObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
    472570{
    473571    LogFlowFuncEnter();
     
    514612                    AssertPtr(pReply);
    515613
    516                     Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN);
     614                    Assert(pReply->uType == VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN);
    517615
    518616                    LogFlowFunc(("hObj=%RU64\n", pReply->u.ObjOpen.uHandle));
     
    540638
    541639/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
    542 DECLCALLBACK(int) shClSvcTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
     640DECLCALLBACK(int) shClSvcTransferIfaceGHObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
    543641{
    544642    LogFlowFuncEnter();
     
    579677                    AssertPtr(pReply);
    580678
    581                     Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE);
     679                    Assert(pReply->uType == VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE);
    582680
    583681                    LogFlowFunc(("hObj=%RU64\n", pReply->u.ObjClose.uHandle));
     
    603701
    604702/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
    605 DECLCALLBACK(int) shClSvcTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
    606                                               void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
     703DECLCALLBACK(int) shClSvcTransferIfaceGHObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
     704                                                void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
    607705{
    608706    LogFlowFuncEnter();
     
    672770
    673771/** @copydoc SHCLTXPROVIDERIFACE::pfnObjWrite */
    674 DECLCALLBACK(int) shClSvcTransferIfaceObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
    675                                                void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
     772DECLCALLBACK(int) shClSvcTransferIfaceHGObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
     773                                                 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
    676774{
    677775    LogFlowFuncEnter();
     
    851949            switch (pReply->uType)
    852950            {
    853                 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
     951                case VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS:
    854952                {
    855953                    if (cParms > idxParm)
     
    860958                }
    861959
    862                 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
     960                case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN:
    863961                {
    864962                    if (cParms > idxParm)
     
    869967                }
    870968
    871                 case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
     969                case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE:
    872970                {
    873971                    if (cParms > idxParm)
     
    878976                }
    879977
    880                 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
     978                case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN:
    881979                {
    882980                    if (cParms > idxParm)
     
    887985                }
    888986
    889                 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
     987                case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE:
    890988                {
    891989                    if (cParms > idxParm)
     
    12491347 * @returns VBox status code.
    12501348 * @param   pClient             Pointer to associated client.
    1251  * @param   pTransfer           Pointer to transfer to handle guest reply for.
     1349 * @param   idTransfer          Transfer ID supplied from the guest.
    12521350 * @param   cParms              Number of function parameters supplied.
    12531351 * @param   aParms              Array function parameters supplied.
    12541352 */
    1255 static int shClSvcTransferHandleReply(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer,
    1256                                       uint32_t cParms, VBOXHGCMSVCPARM aParms[])
    1257 {
    1258     RT_NOREF(pClient, pTransfer);
    1259 
     1353static int shClSvcTransferHandleReply(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
     1354{
    12601355    int rc;
     1356
     1357    PSHCLTRANSFER pTransfer = NULL;
    12611358
    12621359    uint32_t   cbReply = sizeof(SHCLREPLY);
     
    12671364        if (RT_SUCCESS(rc))
    12681365        {
     1366            if (   pReply->uType                    == VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS
     1367                && pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_REQUESTED)
     1368            {
     1369                /* SHCLTRANSFERSTATUS_REQUESTED is special, as it doesn't provide a transfer ID. */
     1370            }
     1371            else /* Everything else needs a valid transfer ID. */
     1372            {
     1373                pTransfer = ShClTransferCtxGetTransferById(&pClient->Transfers.Ctx, idTransfer);
     1374                if (!pTransfer)
     1375                {
     1376                    LogRel2(("Shared Clipboard: Transfer with ID %RU16 not found\n", idTransfer));
     1377                    rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
     1378                }
     1379            }
     1380
     1381            if (RT_FAILURE(rc))
     1382            {
     1383                RTMemFree(pReply);
     1384                pReply = NULL;
     1385
     1386                return rc;
     1387            }
     1388
    12691389            PSHCLEVENTPAYLOAD pPayload
    12701390                = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
     
    12761396                switch (pReply->uType)
    12771397                {
    1278                     case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
     1398                    case VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS:
    12791399                    {
    1280                         LogRel(("Shared Clipboard: Guest reported status %s for transfer %RU32\n",
    1281                                 ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus), pTransfer->State.uID));
     1400                        /* SHCLTRANSFERSTATUS_REQUESTED is special, as it doesn't provide a transfer ID. */
     1401                        if (SHCLTRANSFERSTATUS_REQUESTED == pReply->u.TransferStatus.uStatus)
     1402                        {
     1403                            LogRel2(("Shared Clipboard: Guest requested a new host -> guest transfer\n"));
     1404                        }
     1405                        else
     1406                            LogRel2(("Shared Clipboard: Guest reported status %s for transfer %RU32\n",
     1407                                     ShClTransferStatusToStr(pReply->u.TransferStatus.uStatus), idTransfer));
    12821408
    12831409                        switch (pReply->u.TransferStatus.uStatus)
    12841410                        {
    1285                             case SHCLTRANSFERSTATUS_INITIALIZED: /* Initialized -> Started */
    1286                                 rc = shClSvcTransferStart(pClient, pTransfer);
     1411                            case SHCLTRANSFERSTATUS_REQUESTED: /* Guest requests a H->G transfer. */
     1412                            {
     1413                                uint32_t const uMode = ShClSvcGetMode();
     1414                                if (   uMode == VBOX_SHCL_MODE_HOST_TO_GUEST
     1415                                    || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL)
     1416                                {
     1417                                    /* We only create (but not initialize) the transfer here. This is the most lightweight form of
     1418                                     * having a pending transfer around. Report back the new transfer ID to the guest then. */
     1419                                    if (pTransfer == NULL) /* Must not exist yet. */
     1420                                    {
     1421                                        rc = ShClSvcTransferCreate(pClient, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL,
     1422                                                                   NIL_SHCLTRANSFERID /* Creates a new transfer ID */,
     1423                                                                   &pTransfer);
     1424                                        if (RT_SUCCESS(rc))
     1425                                        {
     1426                                            shClSvcClientLock(pClient);
     1427
     1428                                            rc = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
     1429                                                                                        SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS,
     1430                                                                                        NULL);
     1431                                            shClSvcClientUnlock(pClient);
     1432                                        }
     1433                                    }
     1434                                    else
     1435                                        rc = VERR_WRONG_ORDER;
     1436                                }
     1437                                else
     1438                                    rc = VERR_INVALID_PARAMETER;
     1439
    12871440                                break;
    1288 
    1289                             case SHCLTRANSFERSTATUS_STARTED:
     1441                            }
     1442
     1443                            case SHCLTRANSFERSTATUS_INITIALIZED: /* Guest reports the transfer as being initialized. */
     1444                            {
     1445                                switch (ShClTransferGetDir(pTransfer))
     1446                                {
     1447                                    case SHCLTRANSFERDIR_FROM_REMOTE: /* G->H */
     1448                                        /* Already done locally when creating the transfer. */
     1449                                        break;
     1450
     1451                                    case SHCLTRANSFERDIR_TO_REMOTE:   /* H->G */
     1452                                    {
     1453                                        /* Initialize the transfer on the host side. */
     1454                                        rc = ShClSvcTransferInit(pClient, pTransfer);
     1455                                        break;
     1456                                    }
     1457
     1458                                    default:
     1459                                        AssertFailed();
     1460                                        break;
     1461                                }
     1462
    12901463                                break;
     1464                            }
     1465                            case SHCLTRANSFERSTATUS_STARTED:     /* Guest has started the transfer on its side. */
     1466                            {
     1467                                /* We only need to start for H->G transfers here.
     1468                                 * For G->H transfers we start this as soon as the host clipboard requests data. */
     1469                                if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_TO_REMOTE)
     1470                                {
     1471                                    /* Start the transfer on the host side. */
     1472                                    rc = ShClSvcTransferStart(pClient, pTransfer);
     1473                                }
     1474                                break;
     1475                            }
     1476
     1477                            case SHCLTRANSFERSTATUS_CANCELED:
     1478                                RT_FALL_THROUGH();
     1479                            case SHCLTRANSFERSTATUS_KILLED:
     1480                            {
     1481                                LogRel(("Shared Clipboard: Guest has %s transfer %RU32\n",
     1482                                        pReply->uType == SHCLTRANSFERSTATUS_CANCELED ? "canceled" : "killed", pTransfer->State.uID));
     1483
     1484                                rc = ShClSvcTransferStop(pClient, pTransfer, false /* fWaitForGuest */);
     1485
     1486                                /* Regardless of whether the guest was able to report back and/or stop the transfer, remove the transfer on the host
     1487                                 * so that we don't risk of having stale transfers here. */
     1488                                ShClSvcTransferDestroy(pClient, pTransfer);
     1489                                pTransfer = NULL;
     1490                                break;
     1491                            }
     1492
     1493                            case SHCLTRANSFERSTATUS_STOPPED:
     1494                            {
     1495                                LogRel(("Shared Clipboard: Guest has stopped transfer %RU32\n", pTransfer->State.uID));
     1496
     1497                                rc = ShClSvcTransferStop(pClient, pTransfer, false /* fWaitForGuest */);
     1498                                break;
     1499                            }
    12911500
    12921501                            case SHCLTRANSFERSTATUS_ERROR:
     
    12941503                                LogRel(("Shared Clipboard: Guest reported error %Rrc for transfer %RU32\n",
    12951504                                        pReply->rc, pTransfer->State.uID));
    1296 
    1297                                 rc = shClSvcTransferStop(pClient, pTransfer, false /* fWaitForGuest */);
     1505                                RT_FALL_THROUGH();
     1506                            }
     1507                            default:
     1508                            {
     1509                                /* Regardless of whether the guest was able to report back and/or stop the transfer, remove the transfer on the host
     1510                                 * so that we don't risk of having stale transfers here. */
     1511                                ShClSvcTransferDestroy(pClient, pTransfer);
     1512                                pTransfer = NULL;
    12981513                                break;
    12991514                            }
    1300 
    1301                             default:
    1302                                 rc = shClSvcTransferStop(pClient, pTransfer, true /* fWaitForGuest */);
    1303                                 break;
    13041515                        }
     1516
     1517                        /* Tell the backend. */
     1518                        int rc2 = ShClBackendTransferHandleStatusReply(pClient->pBackend, pClient, pTransfer,
     1519                                                                       SHCLSOURCE_REMOTE, pReply->u.TransferStatus.uStatus,
     1520                                                                       pReply->rc);
     1521                        if (RT_SUCCESS(rc))
     1522                            rc = rc2;
    13051523
    13061524                        RT_FALL_THROUGH();
    13071525                    }
    1308                     case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
     1526                    case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN:
    13091527                        RT_FALL_THROUGH();
    1310                     case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
     1528                    case VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE:
    13111529                        RT_FALL_THROUGH();
    1312                     case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
     1530                    case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN:
    13131531                        RT_FALL_THROUGH();
    1314                     case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
     1532                    case VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE:
    13151533                    {
    13161534                        uint64_t uCID;
     
    13911609    int rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
    13921610
     1611    if (cParms < 1)
     1612        return rc;
     1613    ASSERT_GUEST_RETURN(aParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
     1614
     1615    uint64_t uCID  = 0; /* Context ID */
     1616    rc = HGCMSvcGetU64(&aParms[0], &uCID);
     1617    if (RT_FAILURE(rc))
     1618        return rc;
     1619
     1620    const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
     1621
    13931622    /*
    13941623     * Pre-check: For certain messages we need to make sure that a (right) transfer is present.
    13951624     */
    1396     uint64_t      uCID      = 0; /* Context ID */
    13971625    PSHCLTRANSFER pTransfer = NULL;
    1398 
    1399     shClSvcClientLock(pClient);
    1400     ASSERT_GUEST_MSG_RETURN(pClient->Pending.uType == 0, ("Already pending! (idClient=%RU32)\n",
    1401                                                           pClient->State.uClientID), VERR_RESOURCE_BUSY);
    1402     shClSvcClientUnlock(pClient);
    1403 
    14041626    switch (u32Function)
    14051627    {
     1628        case VBOX_SHCL_GUEST_FN_REPLY:
     1629            /* Function does its own lookup. */
     1630            break;
     1631
    14061632        default:
    14071633        {
    1408             if (!ShClTransferCtxGetTotalTransfers(&pClient->Transfers.Ctx))
    1409             {
    1410                 LogFunc(("No transfers found\n"));
    1411                 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
    1412                 break;
    1413             }
    1414 
    1415             if (cParms < 1)
    1416                 break;
    1417 
    1418             ASSERT_GUEST_RETURN(aParms[0].type == VBOX_HGCM_SVC_PARM_64BIT, VERR_WRONG_PARAMETER_TYPE);
    1419 
    1420             rc = HGCMSvcGetU64(&aParms[0], &uCID);
    1421             if (RT_FAILURE(rc))
    1422                 break;
    1423 
    1424             const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
    1425 
    1426             pTransfer = ShClTransferCtxGetTransferById(&pClient->Transfers.Ctx, uTransferID);
     1634            pTransfer = ShClTransferCtxGetTransferById(&pClient->Transfers.Ctx, idTransfer);
    14271635            if (!pTransfer)
    14281636            {
    1429                 LogFunc(("Transfer with ID %RU16 not found\n", uTransferID));
     1637                LogRel(("Shared Clipboard: Transfer with ID %RU16 not found\n", idTransfer));
    14301638                rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
    14311639            }
     
    14431651        case VBOX_SHCL_GUEST_FN_REPLY:
    14441652        {
    1445             rc = shClSvcTransferHandleReply(pClient, pTransfer, cParms, aParms);
     1653            rc = shClSvcTransferHandleReply(pClient, idTransfer, cParms, aParms);
    14461654            break;
    14471655        }
     
    14581666                && ShClTransferGetDir(pTransfer)    == SHCLTRANSFERDIR_TO_REMOTE)
    14591667            {
    1460                 /* Get roots if this is a local write transfer (host -> guest). */
    1461                 rc = ShClBackendTransferGetRoots(pClient->pBackend, pClient, pTransfer);
     1668                rc = ShClBackendTransferHGRootListRead(pClient->pBackend, pClient, pTransfer);
     1669                if (RT_FAILURE(rc))
     1670                    break;
    14621671            }
    14631672            else
     
    14731682            HGCMSvcSetU32(&aParms[1], rootListHdr.fFeatures);
    14741683            HGCMSvcSetU64(&aParms[2], rootListHdr.cEntries);
    1475 
    1476             rc = VINF_SUCCESS;
    14771684            break;
    14781685        }
     
    18302037    }
    18312038
     2039    /* If anything wrong has happened, make sure to unregister the transfer again (if not done already) and tell the guest. */
     2040    if (   RT_FAILURE(rc)
     2041        && pTransfer)
     2042    {
     2043        shClSvcClientLock(pClient);
     2044
     2045        /* Let the guest know. */
     2046        int rc2 = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
     2047                                                         SHCLTRANSFERSTATUS_ERROR, rc, NULL /* ppEvent */);
     2048        AssertRC(rc2);
     2049
     2050        ShClSvcTransferDestroy(pClient, pTransfer);
     2051
     2052        shClSvcClientUnlock(pClient);
     2053    }
     2054
    18322055    LogFlowFunc(("[Client %RU32] Returning rc=%Rrc\n", pClient->State.uClientID, rc));
    18332056    return rc;
     
    18792102            break;
    18802103    }
     2104
     2105    LogFlowFuncLeaveRC(rc);
     2106    return rc;
     2107}
     2108
     2109/**
     2110 * Reports a transfer status to the guest.
     2111 *
     2112 * @returns VBox status code.
     2113 * @param   pClient             Client that owns the transfer.
     2114 * @param   idTransfer          Transfer ID to report status for.
     2115 * @param   enmDir              Transfer direction to report status for.
     2116 * @param   uStatus             Status to report.
     2117 * @param   rcTransfer          Result code to report. Optional and depending on status.
     2118 * @param   ppEvent             Where to return the wait event on success. Optional.
     2119 *                              Must be released by the caller with ShClEventRelease().
     2120 *
     2121 * @note    Caller must enter the client's critical section.
     2122 */
     2123static int shClSvcTransferSendStatusExAsync(PSHCLCLIENT pClient, SHCLTRANSFERID idTransfer, SHCLTRANSFERDIR enmDir, SHCLTRANSFERSTATUS uStatus,
     2124                                            int rcTransfer, PSHCLEVENT *ppEvent)
     2125{
     2126    AssertPtrReturn(pClient, VERR_INVALID_POINTER);
     2127    AssertReturn(idTransfer != NIL_SHCLTRANSFERID, VERR_INVALID_PARAMETER);
     2128    /* ppEvent is optional. */
     2129
     2130    PSHCLCLIENTMSG pMsgReadData = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
     2131                                                  VBOX_SHCL_CPARMS_TRANSFER_STATUS);
     2132    if (!pMsgReadData)
     2133        return VERR_NO_MEMORY;
     2134
     2135    PSHCLEVENT pEvent;
     2136    int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
     2137    if (RT_SUCCESS(rc))
     2138    {
     2139        HGCMSvcSetU64(&pMsgReadData->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, idTransfer, pEvent->idEvent));
     2140        HGCMSvcSetU32(&pMsgReadData->aParms[1], enmDir);
     2141        HGCMSvcSetU32(&pMsgReadData->aParms[2], uStatus);
     2142        HGCMSvcSetU32(&pMsgReadData->aParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
     2143        HGCMSvcSetU32(&pMsgReadData->aParms[4], 0 /* fFlags, unused */);
     2144
     2145        shClSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
     2146
     2147        rc = shClSvcClientWakeup(pClient);
     2148        if (RT_SUCCESS(rc))
     2149        {
     2150            LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU32 to guest\n",
     2151                     ShClTransferStatusToStr(uStatus), rcTransfer, idTransfer));
     2152
     2153            if (ppEvent)
     2154            {
     2155                *ppEvent = pEvent; /* Takes ownership. */
     2156            }
     2157            else /* If event is not consumed by the caller, release the event again. */
     2158                ShClEventRelease(pEvent);
     2159        }
     2160        else
     2161            ShClEventRelease(pEvent);
     2162    }
     2163    else
     2164        rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     2165
     2166    if (RT_FAILURE(rc))
     2167        LogRel(("Shared Clipboard: Reporting status %s (%Rrc) for transfer %RU32 to guest failed with %Rrc\n",
     2168                ShClTransferStatusToStr(uStatus), rcTransfer, idTransfer, rc));
    18812169
    18822170    LogFlowFuncLeaveRC(rc);
     
    18952183 *                              Must be released by the caller with ShClEventRelease().
    18962184 *
    1897  * @note    Caller must enter critical section.
    1898  */
    1899 int shClSvcTransferSendStatus(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
    1900                               int rcTransfer, PSHCLEVENT *ppEvent)
     2185 * @note    Caller must enter the client's critical section.
     2186 */
     2187static int shClSvcTransferSendStatusAsyncInternal(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
     2188                                                  int rcTransfer, PSHCLEVENT *ppEvent)
    19012189{
    19022190    AssertPtrReturn(pClient,   VERR_INVALID_POINTER);
     
    19042192    /* ppEvent is optional. */
    19052193
    1906     PSHCLCLIENTMSG pMsgReadData = shClSvcMsgAlloc(pClient, VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
    1907                                                   VBOX_SHCL_CPARMS_TRANSFER_STATUS);
    1908     if (!pMsgReadData)
    1909         return VERR_NO_MEMORY;
    1910 
    1911     PSHCLEVENT pEvent;
    1912     int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
    1913     if (RT_SUCCESS(rc))
    1914     {
    1915         HGCMSvcSetU64(&pMsgReadData->aParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
    1916                                                                          pTransfer->State.uID, pEvent->idEvent));
    1917         HGCMSvcSetU32(&pMsgReadData->aParms[1], pTransfer->State.enmDir);
    1918         HGCMSvcSetU32(&pMsgReadData->aParms[2], uStatus);
    1919         HGCMSvcSetU32(&pMsgReadData->aParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
    1920         HGCMSvcSetU32(&pMsgReadData->aParms[4], 0 /* fFlags, unused */);
    1921 
    1922         shClSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
    1923 
    1924         rc = shClSvcClientWakeup(pClient);
    1925         if (RT_SUCCESS(rc))
    1926         {
    1927             LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU32 to guest\n",
    1928                      ShClTransferStatusToStr(uStatus), rcTransfer, pTransfer->State.uID));
    1929 
    1930             if (ppEvent)
    1931             {
    1932                 *ppEvent = pEvent; /* Takes ownership. */
    1933             }
    1934             else /* If event is not consumed by the caller, release the event again. */
    1935                 ShClEventRelease(pEvent);
    1936         }
    1937         else
    1938             ShClEventRelease(pEvent);
    1939     }
    1940     else
    1941         rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
    1942 
    1943     if (RT_FAILURE(rc))
    1944         LogRel(("Shared Clipboard: Reporting status %s (%Rrc) for transfer %RU32 to guest failed with %Rrc\n",
    1945                 ShClTransferStatusToStr(uStatus), rcTransfer, pTransfer->State.uID, rc));
    1946 
    1947     LogFlowFuncLeaveRC(rc);
    1948     return rc;
    1949 }
    1950 
    1951 /**
    1952  * Cleans up (unregisters and destroys) all transfers not in the 'started' state (anymore).
     2194   return shClSvcTransferSendStatusExAsync(pClient, ShClTransferGetID(pTransfer), ShClTransferGetDir(pTransfer),
     2195                                           uStatus, rcTransfer, ppEvent);
     2196}
     2197
     2198int ShClSvcTransferSendStatusAsync(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
     2199                                   int rcTransfer, PSHCLEVENT *ppEvent)
     2200{
     2201    shClSvcClientLock(pClient);
     2202
     2203    int rc = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer, uStatus, rcTransfer, ppEvent);
     2204
     2205    shClSvcClientUnlock(pClient);
     2206
     2207    return rc;
     2208}
     2209
     2210/**
     2211 * Cleans up (unregisters and destroys) all transfers not in started state (anymore).
    19532212 *
    19542213 * @param   pClient             Client to clean up transfers for.
     
    19562215 * @note    Caller needs to take the critical section.
    19572216 */
    1958 void shClSvcTransferCleanupAllUnused(PSHCLCLIENT pClient)
    1959 {
     2217static void shClSvcTransferCleanupAllUnused(PSHCLCLIENT pClient)
     2218{
     2219    Assert(RTCritSectIsOwner(&pClient->CritSect));
     2220
    19602221    LogFlowFuncEnter();
    19612222
    19622223    PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
    19632224
    1964     /* Remove all transfers which are not in a running state (e.g. only announced). */
    19652225    PSHCLTRANSFER pTransfer, pTransferNext;
    19662226    RTListForEachSafe(&pTxCtx->List, pTransfer, pTransferNext, SHCLTRANSFER, Node)
    19672227    {
    1968         if (ShClTransferGetStatus(pTransfer) != SHCLTRANSFERSTATUS_STARTED)
     2228        SHCLTRANSFERSTATUS const enmSts = ShClTransferGetStatus(pTransfer);
     2229        if (enmSts != SHCLTRANSFERSTATUS_STARTED)
    19692230        {
    19702231            /* Let the guest know. */
    1971             int rc2 = shClSvcTransferSendStatus(pClient, pTransfer,
    1972                                                 SHCLTRANSFERSTATUS_UNINITIALIZED, VINF_SUCCESS, NULL /* ppEvent */);
     2232            int rc2 = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
     2233                                                             SHCLTRANSFERSTATUS_UNINITIALIZED, VINF_SUCCESS, NULL /* ppEvent */);
    19732234            AssertRC(rc2);
    19742235
    1975             ShClTransferCtxTransferUnregisterById(pTxCtx, pTransfer->State.uID);
     2236            ShClTransferCtxUnregisterById(pTxCtx, pTransfer->State.uID);
    19762237
    19772238            ShClTransferDestroy(pTransfer);
     
    19842245
    19852246/**
    1986  * Initializes a new transfer and sends the status to the guest.
    1987  *
    1988  * @note Assumes that the client's critical section is taken.
     2247 * Creates a new transfer on the host.
    19892248 *
    19902249 * @returns VBox status code.
    19912250 * @param   pClient             Client that owns the transfer.
    1992  * @param   enmDir              Transfer direction to start.
    1993  * @param   enmSource           Transfer source to start.
    1994  * @param   ppTransfer          Where to return the created transfer on success. Optional.
    1995  */
    1996 int shClSvcTransferInit(PSHCLCLIENT pClient,
    1997                         SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
    1998                         PSHCLTRANSFER *ppTransfer)
    1999 {
    2000     Assert(RTCritSectIsOwner(&pClient->CritSect));
    2001 
     2251 * @param   enmDir              Transfer direction to create.
     2252 * @param   enmSource           Transfer source to create.
     2253 * @param   idTransfer          Transfer ID to use for creation.
     2254 *                              If set to NIL_SHCLTRANSFERID, a new transfer ID will be created.
     2255 * @param   ppTransfer          Where to return the created transfer on success. Optional and can be NULL.
     2256 */
     2257int ShClSvcTransferCreate(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer, PSHCLTRANSFER *ppTransfer)
     2258{
    20022259    AssertPtrReturn(pClient, VERR_INVALID_POINTER);
    20032260    /* ppTransfer is optional. */
     
    20052262    LogFlowFuncEnter();
    20062263
     2264    shClSvcClientLock(pClient);
     2265
     2266    /* When creating a new transfer, this is a good time to clean up old stuff we don't need anymore. */
    20072267    shClSvcTransferCleanupAllUnused(pClient);
    20082268
     2269    PSHCLTRANSFER pTransfer;
     2270    int rc = ShClTransferCreate(enmDir, enmSource, &pTransfer);
     2271    if (RT_SUCCESS(rc))
     2272    {
     2273        if (idTransfer == NIL_SHCLTRANSFERID)
     2274            rc = ShClTransferCtxRegister(&pClient->Transfers.Ctx, pTransfer, &idTransfer);
     2275        else
     2276            rc = ShClTransferCtxRegisterById(&pClient->Transfers.Ctx, pTransfer, idTransfer);
     2277        if (RT_SUCCESS(rc))
     2278        {
     2279            if (ppTransfer)
     2280                *ppTransfer = pTransfer;
     2281        }
     2282    }
     2283
     2284    shClSvcClientUnlock(pClient);
     2285
     2286    if (RT_FAILURE(rc))
     2287    {
     2288        ShClTransferDestroy(pTransfer);
     2289
     2290        RTMemFree(pTransfer);
     2291        pTransfer = NULL;
     2292    }
     2293
     2294    if (RT_FAILURE(rc))
     2295       LogRel(("Shared Clipboard: Creating transfer failed with %Rrc\n", rc));
     2296
     2297    LogFlowFuncLeaveRC(rc);
     2298    return rc;
     2299}
     2300
     2301/**
     2302 * Destroys a transfer on the host.
     2303 *
     2304 * @param   pClient             Client to destroy transfer for.
     2305 * @param   pTransfer           Transfer to destroy.
     2306 *                              The pointer will be invalid after return.
     2307 */
     2308void ShClSvcTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
     2309{
     2310    if (!pTransfer)
     2311        return;
     2312
     2313    LogFlowFuncEnter();
     2314
    20092315    PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
    20102316
     2317    ShClTransferCtxUnregisterById(pTxCtx, pTransfer->State.uID);
     2318
     2319    ShClTransferDestroy(pTransfer);
     2320
     2321    RTMemFree(pTransfer);
     2322    pTransfer = NULL;
     2323
     2324    LogFlowFuncLeave();
     2325}
     2326
     2327/**
     2328 * Initializes a (created) transfer on the host.
     2329 *
     2330 * @returns VBox status code.
     2331 * @param   pClient             Client that owns the transfer.
     2332 * @param   pTransfer           Transfer to initialize.
     2333 */
     2334int ShClSvcTransferInit(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
     2335{
     2336    AssertPtrReturn(pClient, VERR_INVALID_POINTER);
     2337
     2338    LogFlowFuncEnter();
     2339
     2340    shClSvcClientLock(pClient);
     2341
     2342    Assert(ShClTransferGetStatus(pTransfer) == SHCLTRANSFERSTATUS_NONE);
     2343
     2344    PSHCLTRANSFERCTX pTxCtx = &pClient->Transfers.Ctx;
     2345
    20112346    int rc;
    20122347
    2013     if (!ShClTransferCtxTransfersMaximumReached(pTxCtx))
    2014     {
     2348    if (!ShClTransferCtxIsMaximumReached(pTxCtx))
     2349    {
     2350        SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
     2351
    20152352        LogRel2(("Shared Clipboard: Initializing %s transfer ...\n",
    20162353                 enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "guest -> host" : "host -> guest"));
    20172354
    2018         PSHCLTRANSFER pTransfer;
    2019         rc = ShClTransferCreate(&pTransfer);
    2020         if (RT_SUCCESS(rc))
    2021         {
    2022             SHCLTXPROVIDER Provider;
    2023             RT_ZERO(Provider);
    2024 
    2025             /* Assign local provider first and overwrite interface methods below if needed. */
    2026             VBClTransferProviderLocalQueryInterface(&Provider);
    2027 
    2028             if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host. */
    2029             {
    2030                 Provider.Interface.pfnRootListRead  = shClSvcTransferIfaceRootListRead;
    2031 
    2032                 Provider.Interface.pfnListOpen      = shClSvcTransferIfaceListOpen;
    2033                 Provider.Interface.pfnListClose     = shClSvcTransferIfaceListClose;
    2034                 Provider.Interface.pfnListHdrRead   = shClSvcTransferIfaceListHdrRead;
    2035                 Provider.Interface.pfnListEntryRead = shClSvcTransferIfaceListEntryRead;
    2036 
    2037                 Provider.Interface.pfnObjOpen       = shClSvcTransferIfaceObjOpen;
    2038                 Provider.Interface.pfnObjClose      = shClSvcTransferIfaceObjClose;
    2039                 Provider.Interface.pfnObjRead       = shClSvcTransferIfaceObjRead;
    2040             }
    2041             else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Host -> Guest. */
    2042             {
    2043                 Provider.Interface.pfnListHdrWrite   = shClSvcTransferIfaceListHdrWrite;
    2044                 Provider.Interface.pfnListEntryWrite = shClSvcTransferIfaceListEntryWrite;
    2045                 Provider.Interface.pfnObjWrite       = shClSvcTransferIfaceObjWrite;
    2046             }
    2047             else
    2048                 AssertFailed();
    2049 
    2050             Provider.enmSource = pClient->State.enmSource;
    2051             Provider.pvUser    = pClient;
    2052 
    2053             rc = ShClTransferSetProvider(pTransfer, &Provider);
     2355        SHCLTXPROVIDER Provider;
     2356        RT_ZERO(Provider);
     2357
     2358        /* Assign local provider first and overwrite interface methods below if needed. */
     2359        ShClTransferProviderLocalQueryInterface(&Provider);
     2360
     2361        if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host. */
     2362        {
     2363            Provider.Interface.pfnRootListRead  = shClSvcTransferIfaceGHRootListRead;
     2364
     2365            Provider.Interface.pfnListOpen      = shClSvcTransferIfaceGHListOpen;
     2366            Provider.Interface.pfnListClose     = shClSvcTransferIfaceGHListClose;
     2367            Provider.Interface.pfnListHdrRead   = shClSvcTransferIfaceGHListHdrRead;
     2368            Provider.Interface.pfnListEntryRead = shClSvcTransferIfaceGHListEntryRead;
     2369
     2370            Provider.Interface.pfnObjOpen       = shClSvcTransferIfaceGHObjOpen;
     2371            Provider.Interface.pfnObjClose      = shClSvcTransferIfaceGHObjClose;
     2372            Provider.Interface.pfnObjRead       = shClSvcTransferIfaceGHObjRead;
     2373        }
     2374        else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Host -> Guest. */
     2375        {
     2376            Provider.Interface.pfnListHdrWrite   = shClSvcTransferIfaceHGListHdrWrite;
     2377            Provider.Interface.pfnListEntryWrite = shClSvcTransferIfaceHGListEntryWrite;
     2378            Provider.Interface.pfnObjWrite       = shClSvcTransferIfaceHGObjWrite;
     2379        }
     2380        else
     2381            AssertFailed();
     2382
     2383        Provider.enmSource = pClient->State.enmSource;
     2384        Provider.pvUser    = pClient;
     2385
     2386        rc = ShClTransferSetProvider(pTransfer, &Provider);
     2387        if (RT_SUCCESS(rc))
     2388        {
     2389            ShClTransferSetCallbacks(pTransfer, &pClient->Transfers.Callbacks);
     2390
     2391            rc = ShClTransferInit(pTransfer);
    20542392            if (RT_SUCCESS(rc))
    20552393            {
    2056                 ShClTransferSetCallbacks(pTransfer, &pClient->Transfers.Callbacks);
    2057 
    2058                 rc = ShClTransferInit(pTransfer, enmDir, enmSource);
    2059                 if (RT_SUCCESS(rc))
    2060                 {
    2061                     SHCLTRANSFERID uTransferID = 0;
    2062                     rc = ShClTransferCtxTransferRegister(pTxCtx, pTransfer, &uTransferID);
    2063                     if (RT_SUCCESS(rc))
    2064                     {
    2065                         rc = ShClBackendTransferCreate(pClient->pBackend, pClient, pTransfer);
    2066                         if (RT_SUCCESS(rc))
    2067                         {
    2068                             /* Tell the guest that we've initialized the transfer locally. */
    2069                             rc = shClSvcTransferSendStatus(pClient, pTransfer,
    2070                                                            SHCLTRANSFERSTATUS_INITIALIZED, VINF_SUCCESS, NULL /* ppEvent */);
    2071                         }
    2072                     }
    2073 
    2074                     if (RT_FAILURE(rc))
    2075                         ShClTransferCtxTransferUnregisterById(pTxCtx, uTransferID);
    2076                 }
    2077             }
    2078 
    2079             if (RT_FAILURE(rc))
    2080             {
    2081                 ShClBackendTransferDestroy(pClient->pBackend, pClient, pTransfer);
    2082                 ShClTransferDestroy(pTransfer);
    2083 
    2084                 RTMemFree(pTransfer);
    2085                 pTransfer = NULL;
    2086             }
    2087             else
    2088             {
    2089                 if (ppTransfer)
    2090                     *ppTransfer = pTransfer;
    2091             }
    2092         }
    2093 
    2094         if (RT_FAILURE(rc))
    2095             LogRel(("Shared Clipboard: Starting transfer failed with %Rrc\n", rc));
     2394                /* Sanity: Make sure that the transfer we're gonna report as INITIALIZED to the guest
     2395                 *         actually has some root entries set, as the guest can query for those at any time then. */
     2396                if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
     2397                    AssertMsgStmt(ShClTransferRootsCount(pTransfer), ("Transfer has no root entries set\n"), rc = VERR_WRONG_ORDER);
     2398            }
     2399        }
    20962400    }
    20972401    else
    20982402        rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
    20992403
     2404    /* Tell the guest the outcome. */
     2405    int rc2 = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
     2406                                                       RT_SUCCESS(rc)
     2407                                                     ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc,
     2408                                                     NULL /* ppEvent */);
     2409    if (RT_SUCCESS(rc))
     2410        rc2 = rc;
     2411
     2412    if (RT_FAILURE(rc))
     2413        LogRel(("Shared Clipboard: Initializing transfer failed with %Rrc\n", rc));
     2414
     2415    shClSvcClientUnlock(pClient);
     2416
    21002417    LogFlowFuncLeaveRC(rc);
    21012418    return rc;
     
    21072424 * @returns VBox status code.
    21082425 * @param   pClient             Client that owns the transfer.
    2109  * @param   pTransfer           Transfer to stop.
    2110  */
    2111 int shClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
     2426 * @param   pTransfer           Transfer to start.
     2427 */
     2428int ShClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
    21122429{
    21132430    LogRel2(("Shared Clipboard: Starting transfer %RU32 ...\n", pTransfer->State.uID));
     
    21192436    /* Let the guest know in any case
    21202437     * (so that it can tear down the transfer on error as well). */
    2121     int rc2 = shClSvcTransferSendStatus(pClient, pTransfer,
    2122                                         RT_SUCCESS(rc) ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc, NULL /* ppEvent */);
     2438    int rc2 = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
     2439                                                     RT_SUCCESS(rc) ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc,
     2440                                                     NULL /* ppEvent */);
    21232441    if (RT_SUCCESS(rc))
    21242442        rc = rc2;
     
    21362454 * @param   fWaitForGuest       Set to \c true to wait for acknowledgement from guest, or \c false to skip waiting.
    21372455 */
    2138 int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest)
     2456int ShClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest)
    21392457{
    21402458    LogRel2(("Shared Clipboard: Stopping transfer %RU32 ...\n", pTransfer->State.uID));
     
    21432461
    21442462    PSHCLEVENT pEvent;
    2145     int rc = shClSvcTransferSendStatus(pClient, pTransfer,
    2146                                        SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS, &pEvent);
     2463    int rc = shClSvcTransferSendStatusAsyncInternal(pClient, pTransfer,
     2464                                                    SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS, &pEvent);
    21472465    if (   RT_SUCCESS(rc)
    21482466        && fWaitForGuest)
     
    21652483                pTransfer->State.uID, rc));
    21662484
    2167     /* Regardless of whether the guest was able to report back and/or stop the transfer, remove the transfer on the host
    2168      * so that we don't risk of having stale transfers here. */
    2169     int rc2 = ShClTransferCtxTransferUnregisterById(&pClient->Transfers.Ctx, ShClTransferGetID(pTransfer));
    2170     if (RT_SUCCESS(rc2))
    2171     {
    2172         ShClBackendTransferDestroy(pClient->pBackend, pClient, pTransfer);
    2173         ShClTransferDestroy(pTransfer);
    2174         pTransfer = NULL;
    2175     }
    2176 
    2177     if (RT_SUCCESS(rc))
    2178         rc = rc2;
    2179 
    2180     if (RT_FAILURE(rc))
    2181         LogRel(("Shared Clipboard: Stopping transfer %RU32 failed with rc=%Rrc\n",
    2182                 pTransfer->State.uID, rc));
    2183 
    21842485    shClSvcClientUnlock(pClient);
    21852486
     
    22132514            AssertPtr(pClient);
    22142515
    2215             shClSvcClientTransfersReset(pClient);
     2516            shClSvcTransferDestroyAll(pClient);
    22162517
    22172518            ++itClient;
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.h

    r98103 r100367  
    3232#endif
    3333
     34int shClSvcTransferModeSet(uint32_t fMode);
     35int ShClSvcTransferCreate(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer, PSHCLTRANSFER *ppTransfer);
     36void ShClSvcTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
     37int ShClSvcTransferInit(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
     38int ShClSvcTransferStart(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
     39int ShClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, bool fWaitForGuest);
     40int ShClSvcTransferSendStatusAsync(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus, int rcTransfer, PSHCLEVENT *ppEvent);
     41int ShClSvcTransferRootListReadFromGuest(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer);
     42bool shClSvcTransferMsgIsAllowed(uint32_t uMode, uint32_t uMsg);
     43void shClSvcTransferDestroyAll(PSHCLCLIENT pClient);
     44
    3445#endif /* !VBOX_INCLUDED_SRC_SharedClipboard_VBoxSharedClipboardSvc_transfers_h */
    3546
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-win.cpp

    r100205 r100367  
    166166    LogFlowFunc(("uFmt=%#x\n", uFmt));
    167167
    168     int rc;
    169 
    170     PSHCLEVENT pEvent;
    171     rc = ShClSvcReadDataFromGuestAsync(pCtx->pClient, uFmt, &pEvent);
    172     if (RT_SUCCESS(rc))
    173     {
    174         PSHCLEVENTPAYLOAD pPayload;
    175         rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
    176         if (RT_SUCCESS(rc))
    177         {
    178             if (ppvData)
    179                 *ppvData = pPayload ? pPayload->pvData : NULL;
    180             if (pcbData)
    181                 *pcbData = pPayload ? pPayload->cbData : 0;
    182         }
    183 
    184         ShClEventRelease(pEvent);
    185     }
    186 
     168    int rc = ShClSvcReadDataFromGuest(pCtx->pClient, uFmt, &pEvent);
    187169    if (RT_FAILURE(rc))
    188170        LogRel(("Shared Clipboard: Reading guest clipboard data for Windows host failed with %Rrc\n", rc));
     
    231213#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    232214/**
    233  * @copydoc SHCLTRANSFERCALLBACKS::pfnOnStart
    234  *
    235  * Called on transfer start to notify the "in-flight" IDataObject about a started transfer.
     215 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnInitialized
     216 *
     217 * Called on transfer intialization to notify the "in-flight" IDataObject about a data transfer.
    236218 *
    237219 * @thread  Service main thread.
    238220 */
    239 static DECLCALLBACK(void) vboxClipboardSvcWinTransferStartedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     221static DECLCALLBACK(void) vboxClipboardSvcWinTransferInitializedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
    240222{
    241223    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     
    259241            SharedClipboardWinDataObject *pObj = pCtx->Win.pDataObjInFlight;
    260242            AssertPtrReturnVoid(pObj);
    261             rc = pObj->SetAndStartTransfer(pTransfer);
     243            rc = pObj->SetTransfer(pTransfer);
    262244
    263245            pCtx->Win.pDataObjInFlight = NULL; /* Hand off to Windows. */
     
    272254
    273255    LogFlowFunc(("LEAVE: idTransfer=%RU32, rc=%Rrc\n", ShClTransferGetID(pTransfer), rc));
     256}
     257
     258/**
     259 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnDestroy
     260 *
     261 * @thread  Service main thread.
     262 */
     263static DECLCALLBACK(void) vboxClipboardSvcWinTransferDestroyCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     264{
     265    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     266    AssertPtr(pCtx);
     267
     268    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     269    AssertPtr(pTransfer);
     270
     271    SharedClipboardWinTransferDestroy(&pCtx->Win, pTransfer);
     272}
     273
     274/**
     275 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnStarted
     276 *
     277 * @thread  Service main thread.
     278 */
     279static DECLCALLBACK(void) vboxClipboardSvcWinTransferStartedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     280{
     281    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     282    AssertPtr(pCtx);
     283
     284    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     285    AssertPtr(pTransfer);
     286
     287    if (ShClTransferGetDir(pTransfer) ==  SHCLTRANSFERDIR_FROM_REMOTE) /* G->H */
     288    {
     289        /* Report to the guest that we now entered the STARTED state. */
     290        ShClSvcTransferStart(pCtx->pClient, pTransfer);
     291    }
    274292}
    275293#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     
    385403                void    *pvData = NULL;
    386404                uint32_t cbData = 0;
    387                 int rc = vboxClipboardSvcWinReadDataFromGuest(pCtx, uFormat, &pvData, &cbData);
     405                int rc = ShClSvcReadDataFromGuest(pCtx->pClient, uFormat, &pvData, &cbData);
    388406                if (   RT_SUCCESS(rc)
    389407                    && pvData
     
    440458
    441459            int rc = SharedClipboardWinClearAndAnnounceFormats(pWinCtx, fFormats, hWnd);
    442 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    443             if (   RT_SUCCESS(rc)
    444                 && fFormats & VBOX_SHCL_FMT_URI_LIST)
    445             {
    446                 /*
    447                  * The host requested data from the guest as URI list.
    448                  *
    449                  * This means on Windows we
    450                  * - need to first create an own IDataObject and push it on the clipboard
    451                  * - register a transfer locally so that we have a valid ID for it
    452                  *
    453                  * That way Windows will recognize that there is a data transfer "in flight".
    454                  *
    455                  * As soon as the user requests to "paste" the data (transfer), the IDataObject will try to read data via
    456                  * the pfnOnRequestDataFromSource callback.
    457                  */
    458                 SHCLCALLBACKS Callbacks;
    459                 RT_ZERO(Callbacks);
    460                 Callbacks.pfnOnRequestDataFromSource = vboxClipboardSvcWinRequestDataFromSourceCallback;
    461 
    462                 rc = SharedClipboardWinTransferCreateAndSetDataObject(pWinCtx, pCtx, &Callbacks);
    463             }
    464 #endif
    465460            if (RT_FAILURE(rc))
    466461                LogRel(("Shared Clipboard: Reporting clipboard formats %#x to Windows host failed with %Rrc\n", fFormats, rc));
     
    739734         */
    740735        RT_ZERO(pClient->Transfers.Callbacks);
    741         pClient->Transfers.Callbacks.pfnOnStarted = vboxClipboardSvcWinTransferStartedCallback;
     736        pClient->Transfers.Callbacks.pfnOnInitialized = vboxClipboardSvcWinTransferInitializedCallback;
     737        pClient->Transfers.Callbacks.pfnOnStarted     = vboxClipboardSvcWinTransferStartedCallback;
     738        pClient->Transfers.Callbacks.pfnOnDestroy     = vboxClipboardSvcWinTransferDestroyCallback;
    742739
    743740        pClient->Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
     
    973970
    974971#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    975 int ShClBackendTransferCreate(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
    976 {
    977     RT_NOREF(pBackend, pClient, pTransfer);
    978 
    979     LogFlowFuncEnter();
    980 
    981     return VINF_SUCCESS;
    982 }
    983 
    984 int ShClBackendTransferDestroy(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
    985 {
    986     RT_NOREF(pBackend);
    987 
    988     LogFlowFuncEnter();
    989 
    990     SharedClipboardWinTransferDestroy(&pClient->State.pCtx->Win, pTransfer);
    991 
    992     return VINF_SUCCESS;
    993 }
    994 
    995 int ShClBackendTransferGetRoots(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
     972int ShClBackendTransferHGRootListRead(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
    996973{
    997974    RT_NOREF(pBackend);
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp

    r100237 r100367  
    4444#include <iprt/errcore.h>
    4545
    46 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     46#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    4747# include <VBox/GuestHost/SharedClipboard-transfers.h>
     48# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     49#  include <VBox/GuestHost/SharedClipboard-transfers.h>
     50# endif
    4851#endif
    4952
    5053#include "VBoxSharedClipboardSvc-internal.h"
     54#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     55# include "VBoxSharedClipboardSvc-transfers.h"
     56#endif
    5157
    5258/* Number of currently extablished connections. */
     
    8187static DECLCALLBACK(int) shClSvcX11RequestDataFromSourceCallback(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser);
    8288
     89#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     90static DECLCALLBACK(void) shClSvcX11OnTransferInitCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx);
     91static DECLCALLBACK(void) shClSvcX11OnTransferDestroyCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx);
     92static DECLCALLBACK(void) shClSvcX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx);
     93#endif
     94
    8395
    8496int ShClBackendInit(PSHCLBACKEND pBackend, VBOXHGCMSVCFNTABLE *pTable)
     
    146158                pClient->State.pCtx = pCtx;
    147159                pCtx->pClient = pClient;
     160
     161#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     162                /*
     163                 * Set callbacks.
     164                 * Those will be registered within ShClSvcTransferInit() when a new transfer gets initialized.
     165                 *
     166                 * Used for starting / stopping the HTTP server.
     167                 */
     168                RT_ZERO(pClient->Transfers.Callbacks);
     169
     170                pClient->Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
     171                pClient->Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
     172
     173                pClient->Transfers.Callbacks.pfnOnInitialized  = shClSvcX11OnTransferInitCallback;
     174                pClient->Transfers.Callbacks.pfnOnDestroy      = shClSvcX11OnTransferDestroyCallback;
     175                pClient->Transfers.Callbacks.pfnOnUnregistered = shClSvcX11OnTransferUnregisteredCallback;
     176#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    148177
    149178                rc = ShClX11ThreadStart(&pCtx->X11, true /* grab shared clipboard */);
     
    352381}
    353382
     383#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     384/**
     385 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnInitialized
     386 *
     387 * This starts the HTTP server if not done yet and registers the transfer with it.
     388 *
     389 * @thread Service main thread.
     390 */
     391static DECLCALLBACK(void) shClSvcX11OnTransferInitCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     392{
     393    RT_NOREF(pCbCtx);
     394
     395#if 1
     396    LogFlowFuncEnter();
     397
     398    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     399    AssertPtr(pCtx);
     400
     401    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     402    AssertPtr(pTransfer);
     403
     404    switch (ShClTransferGetDir(pTransfer))
     405    {
     406        case SHCLTRANSFERDIR_FROM_REMOTE: /* G->H */
     407        {
     408# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     409            /* We only need to start the HTTP server when we actually receive data from the remote (host). */
     410            ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
     411# endif
     412            break;
     413        }
     414
     415        case SHCLTRANSFERDIR_TO_REMOTE: /* H->G */
     416        {
     417            PSHCLEVENT pEvent;
     418            int rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pClient->EventSrc, &pEvent);
     419            if (RT_SUCCESS(rc))
     420            {
     421                rc = ShClX11ReadDataFromX11Async(&pCtx->X11, VBOX_SHCL_FMT_URI_LIST, UINT32_MAX, pEvent);
     422                if (RT_SUCCESS(rc))
     423                {
     424                    /* X supplies the data asynchronously, so we need to wait for data to arrive first. */
     425                    PSHCLEVENTPAYLOAD pPayload;
     426                    rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     427                    if (RT_SUCCESS(rc))
     428                    {
     429                        if (pPayload)
     430                        {
     431                            Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
     432                            AssertPtr(pPayload->pvData);
     433                            PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
     434
     435                            rc = ShClTransferRootsInitFromStringList(pTransfer,
     436                                                                     (char *)pResp->Read.pvData, pResp->Read.cbData + 1 /* Include zero terminator */);
     437                            //if (RT_SUCCESS(rc))
     438                            //    rc = ShClTransferRootListRead(pTransfer);
     439
     440                            if (RT_SUCCESS(rc))
     441                                LogRel2(("Shared Clipboard: Host reported %RU64 X11 root entries for transfer to guest\n", ShClTransferRootsCount(pTransfer)));
     442
     443                            RTMemFree(pResp->Read.pvData);
     444                            pResp->Read.cbData = 0;
     445
     446                            ShClPayloadFree(pPayload);
     447                            pPayload = NULL;
     448                        }
     449                        else
     450                            rc = VERR_NO_DATA; /* No payload. */
     451                    }
     452                }
     453
     454                ShClEventRelease(pEvent);
     455            }
     456            else
     457                rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     458            break;
     459        }
     460
     461        default:
     462            break;
     463    }
     464
     465    LogFlowFuncLeave();
     466}
     467
     468/**
     469 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnDestroy
     470 *
     471 * This stops the HTTP server if not done yet.
     472 *
     473 * @thread Service main thread.
     474 */
     475static DECLCALLBACK(void) shClSvcX11OnTransferDestroyCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     476{
     477    LogFlowFuncEnter();
     478
     479# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     480    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     481    AssertPtr(pCtx);
     482
     483    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     484    AssertPtr(pTransfer);
     485
     486    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
     487        ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
     488# else
     489    RT_NOREF(pCbCtx);
     490# endif
     491
     492    LogFlowFuncLeave();
     493}
     494
     495/**
     496 * Unregisters a transfer from a HTTP server.
     497 *
     498 * This also stops the HTTP server if no active transfers are found anymore.
     499 *
     500 * @param   pCtx                Shared clipboard context to unregister transfer for.
     501 * @param   pTransfer           Transfer to unregister.
     502 *
     503 * @thread Clipboard main thread.
     504 */
     505static void shClSvcX11HttpTransferUnregister(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
     506{
     507    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
     508    {
     509# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     510        if (ShClTransferHttpServerIsInitialized(&pCtx->X11.HttpCtx.HttpServer))
     511        {
     512            ShClTransferHttpServerUnregisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
     513            ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
     514        }
     515# else
     516        RT_NOREF(pCtx);
     517# endif
     518    }
     519
     520    //ShClTransferRelease(pTransfer);
     521}
     522
     523/**
     524 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnUnregistered
     525 *
     526 * Unregisters a (now) unregistered transfer from the HTTP server.
     527 *
     528 * @thread Clipboard main thread.
     529 */
     530static DECLCALLBACK(void) shClSvcX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
     531{
     532    RT_NOREF(pTransferCtx);
     533    shClSvcX11HttpTransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
     534}
     535#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
     536
    354537/**
    355538 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
     
    373556    }
    374557
    375     int rc = VINF_SUCCESS;
    376 
    377 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     558    PSHCLCLIENT const pClient = pCtx->pClient;
     559    int rc = ShClSvcReadDataFromGuest(pClient, uFmt, ppv, pcb);
     560    if (RT_FAILURE(rc))
     561        return rc;
     562
    378563    /*
    379      * Note: We always return a generic URI list here.
     564     * Note: We always return a generic URI list (as HTTP links) here.
    380565     *       As we don't know which Atom target format was requested by the caller, the X11 clipboard codes needs
    381566     *       to decide & transform the list into the actual clipboard Atom target format the caller wanted.
    382567     */
     568#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    383569    if (uFmt == VBOX_SHCL_FMT_URI_LIST)
    384570    {
    385         PSHCLTRANSFER pTransfer = ShClTransferHttpServerGetTransferFirst(&pCtx->X11.HttpCtx.HttpServer);
    386         if (pTransfer)
    387         {
    388             if (RT_SUCCESS(rc))
    389                 rc = ShClTransferRootListRead(pTransfer);
    390         }
    391 
    392         /** @todo BUGBUG IMPLEMENT THIS! */
    393 
    394         *ppv = NULL;
    395         *pcb = 0;
    396 
    397         rc = VERR_NO_DATA;
    398     }
    399 #endif
    400 
    401     if (RT_SUCCESS(rc))
    402     {
    403         /* Request data from the guest and for data to arrive. */
    404         PSHCLEVENT pEvent;
    405         rc = ShClSvcReadDataFromGuestAsync(pCtx->pClient, uFmt, &pEvent);
     571        PSHCLTRANSFER pTransfer;
     572        rc = ShClSvcTransferCreate(pClient, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
     573                                   NIL_SHCLTRANSFERID /* Creates a new transfer ID */, &pTransfer);
    406574        if (RT_SUCCESS(rc))
    407575        {
    408             PSHCLEVENTPAYLOAD pPayload;
    409             rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     576            /* Initialize the transfer on the host side. */
     577            rc = ShClSvcTransferInit(pClient, pTransfer);
     578            if (RT_FAILURE(rc))
     579                 ShClSvcTransferDestroy(pClient, pTransfer);
     580        }
     581
     582        if (RT_SUCCESS(rc))
     583        {
     584            /* We have to wait for the guest reporting the transfer as being initialized.
     585             * Only then we can start reading stuff. */
     586            rc = ShClTransferWaitForStatus(pTransfer, SHCL_TIMEOUT_DEFAULT_MS, SHCLTRANSFERSTATUS_INITIALIZED);
    410587            if (RT_SUCCESS(rc))
    411588            {
    412                 if (   !pPayload
    413                     || !pPayload->cbData)
     589                rc = ShClTransferRootListRead(pTransfer);
     590                if (RT_SUCCESS(rc))
    414591                {
    415                     rc = VERR_NO_DATA;
    416                 }
    417                 else
    418                 {
    419                     *ppv = pPayload->pvData;
    420                     *pcb = pPayload->cbData;
     592# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     593                    /* As soon as we register the transfer with the HTTP server, the transfer needs to have its roots set. */
     594                    PSHCLHTTPSERVER const pHttpSrv = &pCtx->X11.HttpCtx.HttpServer;
     595                    rc = ShClTransferHttpServerRegisterTransfer(pHttpSrv, pTransfer);
     596                    if (RT_SUCCESS(rc))
     597                    {
     598                        char *pszURL = ShClTransferHttpServerGetUrlA(pHttpSrv, pTransfer->State.uID);
     599                        if (pszURL)
     600                        {
     601                            *ppv = pszURL;
     602                            *pcb = strlen(pszURL) + 1 /* Include terminator */;
     603
     604                            LogFlowFunc(("URL is '%s'\n", pszURL));
     605
     606                            /* ppv has ownership of pszURL. */
     607
     608                            rc = VINF_SUCCESS;
     609                        }
     610                        else
     611                            rc = VERR_NO_MEMORY;
     612                    }
     613# else
     614                    rc = VERR_NOT_SUPPORTED;
     615# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
    421616                }
    422617            }
    423 
    424             ShClEventRelease(pEvent);
    425         }
    426     }
     618        }
     619    }
     620#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    427621
    428622    if (RT_FAILURE(rc))
    429         LogRel(("Shared Clipboard: Requesting data in format %#x for X11 host failed with %Rrc\n", uFmt, rc));
     623        LogRel(("Shared Clipboard: Requesting X11 data in format %#x from guest failed with %Rrc\n", uFmt, rc));
    430624
    431625    LogFlowFuncLeaveRC(rc);
     
    434628
    435629#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    436 
    437 int ShClBackendTransferCreate(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
     630/**
     631 * Handles transfer status replies from the guest.
     632 */
     633int ShClBackendTransferHandleStatusReply(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLSOURCE enmSource, SHCLTRANSFERSTATUS enmStatus, int rcStatus)
     634{
     635    RT_NOREF(pBackend, pClient, enmSource, rcStatus);
     636
     637    PSHCLCONTEXT pCtx = pClient->State.pCtx; RT_NOREF(pCtx);
     638
     639    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host */
     640    {
     641        switch (enmStatus)
     642        {
     643            case SHCLTRANSFERSTATUS_INITIALIZED:
     644            {
     645#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
     646                int rc2 = ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
     647                if (RT_SUCCESS(rc2))
     648                {
     649
     650                }
     651
     652                if (RT_FAILURE(rc2))
     653                    LogRel(("Shared Clipboard: Registering HTTP transfer failed: %Rrc\n", rc2));
     654#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
     655                break;
     656            }
     657
     658            default:
     659                break;
     660        }
     661    }
     662
     663    return VINF_SUCCESS;
     664}
     665
     666int ShClBackendTransferHGRootListRead(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
    438667{
    439668    RT_NOREF(pBackend);
    440 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
    441     /* We only need to start the HTTP server (and register the transfer to it) when we actually receive data from the guest. */
    442     if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
    443         return ShClTransferHttpServerMaybeStart(&pClient->State.pCtx->X11.HttpCtx);
     669
     670#if 1
     671    RT_NOREF(pClient, pTransfer);
     672    int rc = 0;
    444673#else
    445     RT_NOREF(pClient, pTransfer);
    446 #endif
    447     return VINF_SUCCESS;
    448 }
    449 
    450 int ShClBackendTransferDestroy(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
    451 {
    452     RT_NOREF(pBackend);
    453 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
    454     /* See comment in ShClBackendTransferCreate(). */
    455     if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
    456         return ShClTransferHttpServerMaybeStop(&pClient->State.pCtx->X11.HttpCtx);
    457 #else
    458     RT_NOREF(pClient, pTransfer);
    459 #endif
    460     return VINF_SUCCESS;
    461 }
    462 
    463 int ShClBackendTransferGetRoots(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
    464 {
    465     RT_NOREF(pBackend);
    466 
    467674    LogFlowFuncEnter();
    468675
     
    508715    else
    509716        rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
     717#endif
    510718
    511719    LogFlowFuncLeaveRC(rc);
  • trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc.cpp

    r100204 r100367  
    614614
    615615    /* Make sure to send a quit message to the guest so that it can terminate gracefully. */
    616     RTCritSectEnter(&pClient->CritSect);
     616    shClSvcClientLock(pClient);
     617
    617618    if (pClient->Pending.uType)
    618619    {
     
    627628        pClient->Pending.paParms = NULL;
    628629    }
    629     RTCritSectLeave(&pClient->CritSect);
     630
     631#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     632    shClSvcTransferDestroyAll(pClient);
     633    ShClTransferCtxDestroy(&pClient->Transfers.Ctx);
     634#endif
    630635
    631636    ShClEventSourceDestroy(&pClient->EventSrc);
     637
     638    shClSvcClientUnlock(pClient);
    632639
    633640    shClSvcClientStateDestroy(&pClient->State);
     
    635642    PSHCLCLIENTLEGACYCID pCidIter, pCidIterNext;
    636643    RTListForEachSafe(&pClient->Legacy.lstCID, pCidIter, pCidIterNext, SHCLCLIENTLEGACYCID, Node)
    637     {
    638644        RTMemFree(pCidIter);
    639     }
    640645
    641646    int rc2 = RTCritSectDelete(&pClient->CritSect);
     
    686691
    687692#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    688     shClSvcClientTransfersReset(pClient);
     693    shClSvcTransferDestroyAll(pClient);
    689694#endif
    690695
     
    12201225
    12211226/**
    1222  * Requests to read clipboard data from the guest.
     1227 * Reads clipboard data from the guest, asynchronous version.
    12231228 *
    12241229 * @returns VBox status code.
     
    13301335                }
    13311336
    1332 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
     1337#if 0 /* ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    13331338                /*
    13341339                 * When the host wants to read URI data from the guest:
    13351340                 *   - Initialize a transfer locally.
    13361341                 *   - Request URI data from the guest; this tells the guest to initialize a transfer on the guest side.
    1337                  *   - Start the transfer locally once we receive the transfer STARTED status from the guest via VBOX_SHCL_GUEST_FN_REPLY.
     1342                 *   - Start the transfer locally once we receive the transfer INITIALIZED status from the guest via VBOX_SHCL_GUEST_FN_REPLY.
     1343                 *
     1344                 * When this function returns, the X11 clipboard will try reading the data, so we need to make sure that
     1345                 *   - the local HTTP server is up and running (will be done in ShClBackendTransferCreate() on X11)
     1346                 *   - the right (HTTP) URL data is filled into the clipboard
     1347                 * by then.
    13381348                 */
    13391349                if (   RT_SUCCESS(rc)
    1340                     && fFormat == VBOX_SHCL_FMT_URI_LIST)
     1350                    && (fFormat & VBOX_SHCL_FMT_URI_LIST))
    13411351                {
    1342                     rc = shClSvcTransferInit(pClient, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
    1343                                              NULL /* pTransfer */);
     1352                    PSHCLTRANSFER pTransfer;
     1353                    rc = ShClSvcTransferInit(pClient, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE, &pTransfer);
    13441354                    if (RT_SUCCESS(rc))
    13451355                        rc = shClSvcSetSource(pClient, SHCLSOURCE_REMOTE);
     
    13811391
    13821392/**
     1393 * Reads clipboard data from the guest.
     1394 *
     1395 * @returns VBox status code.
     1396 * @param   pClient             Client to request to read data form.
     1397 * @param   fFormats            The formats being requested, OR'ed together (VBOX_SHCL_FMT_XXX).
     1398 * @param   ppv                 Where to return the allocated data read.
     1399 *                              Must be free'd by the caller.
     1400 * @param   pcb                 Where to return number of bytes read.
     1401 */
     1402int ShClSvcReadDataFromGuest(PSHCLCLIENT pClient, SHCLFORMAT fFormats, void **ppv, uint32_t *pcb)
     1403{
     1404    LogFlowFuncEnter();
     1405
     1406    /* Request data from the guest and wait for data to arrive. */
     1407    PSHCLEVENT pEvent;
     1408    int rc = ShClSvcReadDataFromGuestAsync(pClient, fFormats, &pEvent);
     1409    if (RT_SUCCESS(rc))
     1410    {
     1411        PSHCLEVENTPAYLOAD pPayload;
     1412        rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     1413        if (RT_SUCCESS(rc))
     1414        {
     1415            if (   !pPayload
     1416                || !pPayload->cbData)
     1417            {
     1418                rc = VERR_NO_DATA;
     1419            }
     1420            else
     1421            {
     1422                *ppv = pPayload->pvData;
     1423                *pcb = pPayload->cbData;
     1424            }
     1425        }
     1426
     1427        ShClEventRelease(pEvent);
     1428    }
     1429
     1430    if (RT_FAILURE(rc))
     1431        LogRel(("Shared Clipboard: Reading data from guest failed with %Rrc\n", rc));
     1432
     1433    LogFlowFuncLeaveRC(rc);
     1434    return rc;
     1435}
     1436
     1437/**
    13831438 * Signals the host that clipboard data from the guest has been received.
    13841439 *
     
    15751630     */
    15761631    int rc;
    1577     if (!fFormats && pClient->State.enmSource != SHCLSOURCE_REMOTE)
     1632    if (!fFormats)
    15781633        rc = VINF_SUCCESS;
    15791634    else
    15801635    {
    1581         rc = shClSvcSetSource(pClient, SHCLSOURCE_REMOTE);
     1636        rc = RTCritSectEnter(&g_CritSect);
    15821637        if (RT_SUCCESS(rc))
    15831638        {
    1584             rc = RTCritSectEnter(&g_CritSect);
    1585             if (RT_SUCCESS(rc))
     1639            if (g_ExtState.pfnExtension)
    15861640            {
    1587                 if (g_ExtState.pfnExtension)
    1588                 {
    1589                     SHCLEXTPARMS parms;
    1590                     RT_ZERO(parms);
    1591                     parms.uFormat = fFormats;
    1592 
    1593                     g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE, &parms, sizeof(parms));
    1594                 }
    1595                 else
    1596                 {
    1597 #ifdef LOG_ENABLED
    1598                     char *pszFmts = ShClFormatsToStrA(fFormats);
    1599                     if (pszFmts)
    1600                     {
    1601                         LogRel2(("Shared Clipboard: Guest reported formats '%s' to host\n", pszFmts));
    1602                         RTStrFree(pszFmts);
    1603                     }
    1604 #endif
    1605                     rc = ShClBackendReportFormats(&g_ShClBackend, pClient, fFormats);
    1606                     if (RT_FAILURE(rc))
    1607                         LogRel(("Shared Clipboard: Reporting guest clipboard formats to the host failed with %Rrc\n", rc));
    1608                 }
    1609 
    1610                 RTCritSectLeave(&g_CritSect);
     1641                SHCLEXTPARMS parms;
     1642                RT_ZERO(parms);
     1643                parms.uFormat = fFormats;
     1644
     1645                g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE, &parms, sizeof(parms));
    16111646            }
    16121647            else
    1613                 LogRel2(("Shared Clipboard: Unable to take internal lock while receiving guest clipboard announcement: %Rrc\n", rc));
    1614         }
     1648            {
     1649#ifdef LOG_ENABLED
     1650                char *pszFmts = ShClFormatsToStrA(fFormats);
     1651                if (pszFmts)
     1652                {
     1653                    LogRel2(("Shared Clipboard: Guest reported formats '%s' to host\n", pszFmts));
     1654                    RTStrFree(pszFmts);
     1655                }
     1656#endif
     1657                rc = ShClBackendReportFormats(&g_ShClBackend, pClient, fFormats);
     1658                if (RT_FAILURE(rc))
     1659                    LogRel(("Shared Clipboard: Reporting guest clipboard formats to the host failed with %Rrc\n", rc));
     1660            }
     1661
     1662            RTCritSectLeave(&g_CritSect);
     1663        }
     1664        else
     1665            LogRel2(("Shared Clipboard: Unable to take internal lock while receiving guest clipboard announcement: %Rrc\n", rc));
    16151666    }
    16161667
     
    17621813        else
    17631814            LogRel(("Shared Clipboard: Reading host clipboard data failed with %Rrc\n", rc));
    1764 
    1765 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    1766         /*
    1767          * When we receive a read request for URI data:
    1768          *   - Initialize a transfer locally.
    1769          *   - Tell the guest to initialize a transfer on the guest side.
    1770          *   - Start the transfer locally once we receive the transfer STARTED status from the guest via VBOX_SHCL_GUEST_FN_REPLY.
    1771          */
    1772         if (uFormat == VBOX_SHCL_FMT_URI_LIST) /* Only init a transfer if we supply an URI list. */
    1773         {
    1774             shClSvcClientLock(pClient);
    1775 
    1776             rc = shClSvcTransferInit(pClient, SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL,
    1777                                      NULL /* pTransfer */);
    1778             if (RT_SUCCESS(rc))
    1779                 rc = shClSvcSetSource(pClient, SHCLSOURCE_LOCAL);
    1780 
    1781             if (RT_FAILURE(rc))
    1782                 LogRel(("Shared Clipboard: Initializing host -> guest transfer failed with %Rrc\n", rc));
    1783 
    1784             shClSvcClientUnlock(pClient);
    1785         }
    1786 #endif
    17871815    }
    17881816
     
    19982026}
    19992027
    2000 /**
    2001  * Sets the transfer source type of a Shared Clipboard client.
    2002  *
    2003  * @returns VBox status code.
    2004  * @param   pClient             Client to set transfer source type for.
    2005  * @param   enmSource           Source type to set.
    2006  */
    2007 int shClSvcSetSource(PSHCLCLIENT pClient, SHCLSOURCE enmSource)
    2008 {
    2009     if (!pClient) /* If no client connected (anymore), bail out. */
    2010         return VINF_SUCCESS;
    2011 
    2012     int rc = VINF_SUCCESS;
    2013 
    2014     pClient->State.enmSource = enmSource;
    2015 
    2016     LogFlowFunc(("Source of client %RU32 is now %RU32\n", pClient->State.uClientID, pClient->State.enmSource));
    2017 
    2018     LogFlowFuncLeaveRC(rc);
    2019     return rc;
    2020 }
    2021 
    20222028static int svcInit(VBOXHGCMSVCFNTABLE *pTable)
    20232029{
     
    20692075        g_ExtState.uClientID = 0;
    20702076    }
    2071 
    2072 #ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    2073     shClSvcClientTransfersReset(pClient);
    2074 #endif
    20752077
    20762078    ShClBackendDisconnect(&g_ShClBackend, pClient);
     
    22502252
    22512253#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    2252                 shClSvcClientTransfersReset(pClient);
     2254                /* Reset transfer state. */
     2255                shClSvcTransferDestroyAll(pClient);
    22532256#endif
    22542257                shClSvcClientUnlock(pClient);
  • trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardServiceHost.cpp

    r100204 r100367  
    330330
    331331#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
    332 int ShClBackendTransferCreate(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; }
    333 int ShClBackendTransferDestroy(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; }
    334 int ShClBackendTransferGetRoots(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; }
     332int ShClBackendTransferHandleStatusReply(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER, SHCLSOURCE, SHCLTRANSFERSTATUS, int) { return VINF_SUCCESS; }
     333int ShClBackendTransferHGRootListRead(PSHCLBACKEND, PSHCLCLIENT, PSHCLTRANSFER) { return VINF_SUCCESS; }
    335334#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
    336335
  • trunk/src/VBox/HostServices/SharedClipboard/testcase/tstClipboardTransfers.cpp

    r100204 r100367  
    212212{
    213213    PSHCLTRANSFER pTransfer;
    214     int rc = ShClTransferCreate(&pTransfer);
     214    int rc = ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, &pTransfer);
    215215    RTTESTI_CHECK_RC_OK(rc);
    216216
    217217    SHCLTXPROVIDER Provider;
    218     RTTESTI_CHECK(VBClTransferProviderLocalQueryInterface(&Provider) != NULL);
     218    RTTESTI_CHECK(ShClTransferProviderLocalQueryInterface(&Provider) != NULL);
    219219    RTTESTI_CHECK_RC_OK(ShClTransferSetProvider(pTransfer, &Provider));
    220220
     
    246246
    247247    PSHCLTRANSFER pTransfer;
    248     int rc = ShClTransferCreate(&pTransfer);
     248    int rc = ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, &pTransfer);
    249249    RTTESTI_CHECK_RC_OK(rc);
    250250
    251251    SHCLTXPROVIDER Provider;
    252     VBClTransferProviderLocalQueryInterface(&Provider);
     252    ShClTransferProviderLocalQueryInterface(&Provider);
    253253
    254254    rc = ShClTransferSetProvider(pTransfer, &Provider);
    255255    RTTESTI_CHECK_RC_OK(rc);
    256256
    257     rc = ShClTransferInit(pTransfer, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_LOCAL);
     257    rc = ShClTransferInit(pTransfer);
    258258    RTTESTI_CHECK_RC_OK(rc);
    259259
     
    309309    RTTESTI_CHECK_RC_OK(rc);
    310310    PSHCLTRANSFER pTransfer;
    311     rc = ShClTransferCreate(&pTransfer);
     311    rc = ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, &pTransfer);
    312312    RTTESTI_CHECK_RC_OK(rc);
    313313    rc = ShClTransferDestroy(pTransfer);
     
    318318    PSHCLLIST pList = ShClTransferListAlloc();
    319319    RTTESTI_CHECK(pList != NULL);
    320     rc = ShClTransferCreate(&pTransfer);
     320    rc = ShClTransferCreate(SHCLTRANSFERDIR_TO_REMOTE, SHCLSOURCE_LOCAL, &pTransfer);
    321321    RTTESTI_CHECK_RC_OK(rc);
    322322    ShClTransferListFree(pList);
Note: See TracChangeset for help on using the changeset viewer.

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