VirtualBox

Ignore:
Timestamp:
Jul 4, 2023 4:23:18 PM (21 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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/x11/VBoxClient/clipboard-x11.cpp

    r100286 r100367  
    5757#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
    5858/**
    59  * Worker for waiting for a transfer status change.
    60  */
    61 static DECLCALLBACK(int) vbclX11TransferWaitForStatusWorker(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS enmSts,
    62                                                             RTMSINTERVAL msTimeout)
    63 {
    64     RT_NOREF(pCtx);
    65 
    66     LogFlowFuncEnter();
    67 
    68     int rc = VERR_TIMEOUT;
    69 
    70     ShClTransferAcquire(pTransfer);
    71 
    72     uint64_t const tsStartMs = RTTimeMilliTS();
    73 
    74     while (RTTimeMilliTS() - tsStartMs <= msTimeout)
    75     {
    76         if (ShClTransferGetStatus(pTransfer) == enmSts) /* Currently we only have busy waiting here. */
    77         {
    78             rc = VINF_SUCCESS;
    79             break;
    80         }
    81         RTThreadSleep(100);
    82     }
    83 
    84     ShClTransferRelease(pTransfer);
    85 
    86     return rc;
    87 }
    88 
    89 /**
    90  * @copydoc SHCLTRANSFERCALLBACKS::pfnOnRegistered
    91  *
    92  * This starts the HTTP server if not done yet and registers the transfer with it.
     59 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnInitialized
    9360 *
    9461 * @thread Clipboard main thread.
    9562 */
    96 static DECLCALLBACK(void) vbclX11OnHttpTransferRegisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
    97 {
    98     RT_NOREF(pTransferCtx);
    99 
     63static DECLCALLBACK(void) vbclX11OnTransferInitializedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
     64{
    10065    LogFlowFuncEnter();
    10166
     
    10671    AssertPtr(pTransfer);
    10772
    108     ShClTransferAcquire(pTransfer);
     73    int rc = VINF_SUCCESS;
     74
     75    /* If this is a G->H transfer, we need to set the root list entries here, as the host
     76     * will start reading those as soon as we report the INITIALIZED status. */
     77    switch (ShClTransferGetDir(pTransfer))
     78    {
     79        case SHCLTRANSFERDIR_TO_REMOTE: /* G->H */
     80        {
     81            PSHCLEVENT pEvent;
     82            rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->EventSrc, &pEvent);
     83            if (RT_SUCCESS(rc))
     84            {
     85                rc = ShClX11ReadDataFromX11Async(&g_Ctx.X11, VBOX_SHCL_FMT_URI_LIST, UINT32_MAX, pEvent);
     86                if (RT_SUCCESS(rc))
     87                {
     88                    PSHCLEVENTPAYLOAD pPayload;
     89                    rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
     90                    if (RT_SUCCESS(rc))
     91                    {
     92                        if (pPayload)
     93                        {
     94                            Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
     95                            PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
     96
     97                            rc = ShClTransferRootsInitFromStringList(pTransfer, (const char *)pResp->Read.pvData, pResp->Read.cbData);
     98
     99                            RTMemFree(pResp->Read.pvData);
     100                            pResp->Read.cbData = 0;
     101
     102                            ShClPayloadFree(pPayload);
     103                        }
     104                    }
     105                }
     106            }
     107            break;
     108        }
     109
     110        case SHCLTRANSFERDIR_FROM_REMOTE: /* H->G */
     111        {
     112            /* Retrieve the root entries as a first action, so that the transfer is ready to go
     113             * once it gets registered to HTTP server. */
     114            int rc2 = ShClTransferRootListRead(pTransfer);
     115            if (   RT_SUCCESS(rc2)
     116                /* As soon as we register the transfer with the HTTP server, the transfer needs to have its roots set. */
     117                && ShClTransferRootsCount(pTransfer))
     118            {
     119                rc2 = ShClTransferHttpServerRegisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
     120            }
     121            break;
     122        }
     123
     124        default:
     125            break;
     126    }
     127
     128    LogFlowFuncLeaveRC(rc);
     129}
     130
     131/**
     132 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnRegistered
     133 *
     134 * This starts the HTTP server if not done yet and registers the transfer with it.
     135 *
     136 * @thread Clipboard main thread.
     137 */
     138static DECLCALLBACK(void) vbclX11OnTransferRegisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
     139{
     140    RT_NOREF(pTransferCtx);
     141
     142    LogFlowFuncEnter();
     143
     144    PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
     145    AssertPtr(pCtx);
     146
     147    PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
     148    AssertPtr(pTransfer);
    109149
    110150    /* We only need to start the HTTP server when we actually receive data from the remote (host). */
    111     if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
    112     {
    113         /* Retrieve the root entries as a first action, so that the transfer is ready to go
    114          * once it gets registered to HTTP server below. */
    115         int rc2 = ShClTransferRootListRead(pTransfer);
    116         if (RT_SUCCESS(rc2))
    117         {
    118             ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
    119             rc2 = ShClTransferHttpServerRegisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
    120         }
    121 
     151    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
     152    {
     153        int rc2 = ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
    122154        if (RT_FAILURE(rc2))
    123155            LogRel(("Shared Clipboard: Registering HTTP transfer failed: %Rrc\n", rc2));
     
    137169 * @thread Clipboard main thread.
    138170 */
    139 static void vbclX11HttpTransferUnregister(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
     171static void vbclX11TransferUnregister(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
    140172{
    141173    if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
    142174    {
    143         ShClTransferHttpServerUnregisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
    144         ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
    145     }
    146 
    147     ShClTransferRelease(pTransfer);
     175        if (ShClTransferHttpServerIsInitialized(&pCtx->X11.HttpCtx.HttpServer))
     176        {
     177            ShClTransferHttpServerUnregisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
     178            ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
     179        }
     180    }
    148181}
    149182
     
    155188 * @thread Clipboard main thread.
    156189 */
    157 static DECLCALLBACK(void) vbclX11OnHttpTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
     190static DECLCALLBACK(void) vbclX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
    158191{
    159192    RT_NOREF(pTransferCtx);
    160     vbclX11HttpTransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
     193    vbclX11TransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
    161194}
    162195
     
    168201 * @thread Clipboard main thread.
    169202 */
    170 static DECLCALLBACK(void) vbclX11OnHttpTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rc)
     203static DECLCALLBACK(void) vbclX11OnTransferCompletedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rc)
    171204{
    172205    RT_NOREF(rc);
    173     vbclX11HttpTransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
     206    vbclX11TransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
    174207}
    175208
     
    180213 * @thread Clipboard main thread.
    181214 */
    182 static DECLCALLBACK(void) vbclX11OnHttpTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCtx, int rc)
    183 {
    184     return vbclX11OnHttpTransferCompletedCallback(pCtx, rc);
     215static DECLCALLBACK(void) vbclX11OnTransferErrorCallback(PSHCLTRANSFERCALLBACKCTX pCtx, int rc)
     216{
     217    return vbclX11OnTransferCompletedCallback(pCtx, rc);
    185218}
    186219#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
     
    257290 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
    258291 *
    259  * Requests URI data from the host.
    260  * This initiates a transfer on the host. Most of the handling will be done VbglR3 then.
     292 * Requests data from the host.
     293 *
     294 * For transfers: This requests a transfer from the host. Most of the handling will be done VbglR3 then.
    261295 *
    262296 * @thread  X11 event thread.
     
    274308    if (uFmt == VBOX_SHCL_FMT_URI_LIST)
    275309    {
    276         PSHCLHTTPSERVER pSrv = &pCtx->X11.HttpCtx.HttpServer;
    277 
    278310        rc = vbclX11ReadDataWorker(pCtx, uFmt, ppv, pcb, pvUser);
    279311        if (RT_SUCCESS(rc))
    280             rc = ShClTransferHttpServerWaitForStatusChange(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED, 5000 /* SHCL_TIMEOUT_DEFAULT_MS */);
    281         if (RT_SUCCESS(rc))
    282         {
    283             PSHCLTRANSFER pTransfer = ShClTransferHttpServerGetTransferLast(pSrv);
    284             if (pTransfer)
     312        {
     313            /* Request a new H->G transfer from the host.
     314             * This is needed in order to get a transfer ID from the host we can initialize our own local transfer with.
     315             * Transfer creation and set up will be done in VbglR3. */
     316            rc = VbglR3ClipboardTransferRequest(&pCtx->CmdCtx);
     317            if (RT_SUCCESS(rc))
    285318            {
    286                 rc = vbclX11TransferWaitForStatusWorker(pCtx, pTransfer, SHCLTRANSFERSTATUS_STARTED, SHCL_TIMEOUT_DEFAULT_MS);
     319                PSHCLHTTPSERVER pSrv = &pCtx->X11.HttpCtx.HttpServer;
     320
     321                /* Wait until the HTTP server got the transfer registered, so that we have something to work with. */
     322                rc = ShClTransferHttpServerWaitForStatusChange(pSrv, SHCLHTTPSERVERSTATUS_TRANSFER_REGISTERED, SHCL_TIMEOUT_DEFAULT_MS);
    287323                if (RT_SUCCESS(rc))
    288324                {
    289                     char *pszURL = ShClTransferHttpServerGetUrlA(pSrv, pTransfer->State.uID);
    290                     char *pszData = NULL;
    291                     RTStrAPrintf(&pszData, "copy\n%s", pszURL);
    292 
    293                     *ppv = pszData;
    294                     *pcb = strlen(pszData) + 1 /* Include terminator */;
    295 
    296                     LogFlowFunc(("pszURL=%s\n", pszURL));
    297 
    298                     RTStrFree(pszURL);
    299 
    300                     rc = VINF_SUCCESS;
    301                 }
     325                    PSHCLTRANSFER pTransfer = ShClTransferHttpServerGetTransferLast(pSrv);
     326                    if (pTransfer)
     327                    {
     328                        rc = ShClTransferWaitForStatus(pTransfer, SHCL_TIMEOUT_DEFAULT_MS, SHCLTRANSFERSTATUS_INITIALIZED);
     329                        if (RT_SUCCESS(rc))
     330                        {
     331                            char *pszURL = ShClTransferHttpServerGetUrlA(pSrv, pTransfer->State.uID);
     332                            if (pszURL)
     333                            {
     334                                *ppv = pszURL;
     335                                *pcb = strlen(pszURL) + 1 /* Include terminator */;
     336
     337                                LogFlowFunc(("URL is '%s'\n", pszURL));
     338
     339                                /* ppv has ownership of pszURL. */
     340                            }
     341                            else
     342                                rc = VERR_NO_MEMORY;
     343                        }
     344                    }
     345                    else
     346                        AssertMsgFailed(("No registered transfer found for HTTP server\n"));
     347                }
     348                else
     349                    LogRel(("Shared Clipboard: Could not start transfer, as no new HTTP transfer was registered in time\n"));
    302350            }
    303             else
    304                 AssertMsgFailed(("No registered transfer found for HTTP server\n"));
    305         }
    306         else
    307             LogRel(("Shared Clipboard: Could not start transfer, as the HTTP server is not running\n"));
     351        }
    308352    }
    309353    else /* Anything else */
     
    314358
    315359    if (RT_FAILURE(rc))
    316         LogRel(("Requesting data in format %#x from host failed with %Rrc\n", uFmt, rc));
     360        LogRel(("Shared Clipboard: Requesting data in format %#x from host failed with %Rrc\n", uFmt, rc));
    317361
    318362    LogFlowFuncLeaveRC(rc);
     
    418462    pCtx->CmdCtx.Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
    419463
    420     pCtx->CmdCtx.Transfers.Callbacks.pfnOnRegistered   = vbclX11OnHttpTransferRegisteredCallback;
    421     pCtx->CmdCtx.Transfers.Callbacks.pfnOnUnregistered = vbclX11OnHttpTransferUnregisteredCallback;
    422     pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted    = vbclX11OnHttpTransferCompletedCallback;
    423     pCtx->CmdCtx.Transfers.Callbacks.pfnOnError        = vbclX11OnHttpTransferErrorCallback;
     464    pCtx->CmdCtx.Transfers.Callbacks.pfnOnInitialized  = vbclX11OnTransferInitializedCallback;
     465    pCtx->CmdCtx.Transfers.Callbacks.pfnOnRegistered   = vbclX11OnTransferRegisteredCallback;
     466    pCtx->CmdCtx.Transfers.Callbacks.pfnOnUnregistered = vbclX11OnTransferUnregisteredCallback;
     467    pCtx->CmdCtx.Transfers.Callbacks.pfnOnCompleted    = vbclX11OnTransferCompletedCallback;
     468    pCtx->CmdCtx.Transfers.Callbacks.pfnOnError        = vbclX11OnTransferErrorCallback;
    424469# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
    425470#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
Note: See TracChangeset for help on using the changeset viewer.

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