VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-x11.cpp@ 100374

最後變更 在這個檔案從100374是 100374,由 vboxsync 提交於 21 月 前

Shared Clipboard: Initialize the host-backend specific transfer provider callbacks in the SHCLTRANSFERCALLBACKS::pfnOnCreated() callbacks. bugref:9437

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 24.8 KB
 
1/* $Id: VBoxSharedClipboardSvc-x11.cpp 100374 2023-07-05 08:36:57Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Linux host.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
33#include <iprt/assert.h>
34#include <iprt/critsect.h>
35#include <iprt/env.h>
36#include <iprt/mem.h>
37#include <iprt/semaphore.h>
38#include <iprt/string.h>
39#include <iprt/asm.h>
40
41#include <VBox/GuestHost/SharedClipboard.h>
42#include <VBox/GuestHost/SharedClipboard-x11.h>
43#include <VBox/HostServices/VBoxClipboardSvc.h>
44#include <iprt/errcore.h>
45
46#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
47# include <VBox/GuestHost/SharedClipboard-transfers.h>
48# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
49# include <VBox/GuestHost/SharedClipboard-transfers.h>
50# endif
51#endif
52
53#include "VBoxSharedClipboardSvc-internal.h"
54#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
55# include "VBoxSharedClipboardSvc-transfers.h"
56#endif
57
58/* Number of currently extablished connections. */
59static volatile uint32_t g_cShClConnections;
60
61
62/*********************************************************************************************************************************
63* Structures and Typedefs *
64*********************************************************************************************************************************/
65/**
66 * Global context information used by the host glue for the X11 clipboard backend.
67 */
68struct SHCLCONTEXT
69{
70 /** This mutex is grabbed during any critical operations on the clipboard
71 * which might clash with others. */
72 RTCRITSECT CritSect;
73 /** X11 context data. */
74 SHCLX11CTX X11;
75 /** Pointer to the VBox host client data structure. */
76 PSHCLCLIENT pClient;
77 /** We set this when we start shutting down as a hint not to post any new
78 * requests. */
79 bool fShuttingDown;
80};
81
82
83/*********************************************************************************************************************************
84* Prototypes *
85*********************************************************************************************************************************/
86static DECLCALLBACK(int) shClSvcX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser);
87static DECLCALLBACK(int) shClSvcX11RequestDataFromSourceCallback(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser);
88
89#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
90static DECLCALLBACK(void) shClSvcX11OnTransferCreatedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx);
91static DECLCALLBACK(void) shClSvcX11OnTransferInitCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx);
92static DECLCALLBACK(void) shClSvcX11OnTransferDestroyCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx);
93static DECLCALLBACK(void) shClSvcX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx);
94
95static DECLCALLBACK(int) shClSvcX11TransferIfaceHGRootListRead(PSHCLTXPROVIDERCTX pCtx);
96#endif
97
98
99int ShClBackendInit(PSHCLBACKEND pBackend, VBOXHGCMSVCFNTABLE *pTable)
100{
101 RT_NOREF(pBackend);
102
103 LogFlowFuncEnter();
104
105 /* Override the connection limit. */
106 for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
107 pTable->acMaxClients[i] = RT_MIN(VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX, pTable->acMaxClients[i]);
108
109 RT_ZERO(pBackend->Callbacks);
110 /* Use internal callbacks by default. */
111 pBackend->Callbacks.pfnReportFormats = shClSvcX11ReportFormatsCallback;
112 pBackend->Callbacks.pfnOnRequestDataFromSource = shClSvcX11RequestDataFromSourceCallback;
113
114 return VINF_SUCCESS;
115}
116
117void ShClBackendDestroy(PSHCLBACKEND pBackend)
118{
119 RT_NOREF(pBackend);
120
121 LogFlowFuncEnter();
122}
123
124void ShClBackendSetCallbacks(PSHCLBACKEND pBackend, PSHCLCALLBACKS pCallbacks)
125{
126#define SET_FN_IF_NOT_NULL(a_Fn) \
127 if (pCallbacks->pfn##a_Fn) \
128 pBackend->Callbacks.pfn##a_Fn = pCallbacks->pfn##a_Fn;
129
130 SET_FN_IF_NOT_NULL(ReportFormats);
131 SET_FN_IF_NOT_NULL(OnRequestDataFromSource);
132
133#undef SET_FN_IF_NOT_NULL
134}
135
136/**
137 * @note On the host, we assume that some other application already owns
138 * the clipboard and leave ownership to X11.
139 */
140int ShClBackendConnect(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, bool fHeadless)
141{
142 int rc;
143
144 /* Check if maximum allowed connections count has reached. */
145 if (ASMAtomicIncU32(&g_cShClConnections) > VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX)
146 {
147 ASMAtomicDecU32(&g_cShClConnections);
148 LogRel(("Shared Clipboard: maximum amount for client connections reached\n"));
149 return VERR_OUT_OF_RESOURCES;
150 }
151
152 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
153 if (pCtx)
154 {
155 rc = RTCritSectInit(&pCtx->CritSect);
156 if (RT_SUCCESS(rc))
157 {
158 rc = ShClX11Init(&pCtx->X11, &pBackend->Callbacks, pCtx, fHeadless);
159 if (RT_SUCCESS(rc))
160 {
161 pClient->State.pCtx = pCtx;
162 pCtx->pClient = pClient;
163
164#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
165 /*
166 * Set callbacks.
167 * Those will be registered within ShClSvcTransferInit() when a new transfer gets initialized.
168 *
169 * Used for starting / stopping the HTTP server.
170 */
171 RT_ZERO(pClient->Transfers.Callbacks);
172
173 pClient->Transfers.Callbacks.pvUser = pCtx; /* Assign context as user-provided callback data. */
174 pClient->Transfers.Callbacks.cbUser = sizeof(SHCLCONTEXT);
175
176 pClient->Transfers.Callbacks.pfnOnCreated = shClSvcX11OnTransferCreatedCallback;
177 pClient->Transfers.Callbacks.pfnOnInitialized = shClSvcX11OnTransferInitCallback;
178 pClient->Transfers.Callbacks.pfnOnDestroy = shClSvcX11OnTransferDestroyCallback;
179 pClient->Transfers.Callbacks.pfnOnUnregistered = shClSvcX11OnTransferUnregisteredCallback;
180#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
181
182 rc = ShClX11ThreadStart(&pCtx->X11, true /* grab shared clipboard */);
183 if (RT_FAILURE(rc))
184 ShClX11Destroy(&pCtx->X11);
185 }
186
187 if (RT_FAILURE(rc))
188 RTCritSectDelete(&pCtx->CritSect);
189 }
190
191 if (RT_FAILURE(rc))
192 {
193 pClient->State.pCtx = NULL;
194 RTMemFree(pCtx);
195 }
196 }
197 else
198 rc = VERR_NO_MEMORY;
199
200 if (RT_FAILURE(rc))
201 {
202 /* Restore active connections count. */
203 ASMAtomicDecU32(&g_cShClConnections);
204 }
205
206 LogFlowFuncLeaveRC(rc);
207 return rc;
208}
209
210int ShClBackendSync(PSHCLBACKEND pBackend, PSHCLCLIENT pClient)
211{
212 RT_NOREF(pBackend);
213
214 LogFlowFuncEnter();
215
216 /* Tell the guest we have no data in case X11 is not available. If
217 * there is data in the host clipboard it will automatically be sent to
218 * the guest when the clipboard starts up. */
219 if (ShClSvcIsBackendActive())
220 return ShClSvcHostReportFormats(pClient, VBOX_SHCL_FMT_NONE);
221 return VINF_SUCCESS;
222}
223
224/**
225 * Shuts down the shared clipboard service and "disconnect" the guest.
226 * Note! Host glue code
227 */
228int ShClBackendDisconnect(PSHCLBACKEND pBackend, PSHCLCLIENT pClient)
229{
230 RT_NOREF(pBackend);
231
232 LogFlowFuncEnter();
233
234 PSHCLCONTEXT pCtx = pClient->State.pCtx;
235 AssertPtr(pCtx);
236
237 /* Drop the reference to the client, in case it is still there. This
238 * will cause any outstanding clipboard data requests from X11 to fail
239 * immediately. */
240 pCtx->fShuttingDown = true;
241
242 int rc = ShClX11ThreadStop(&pCtx->X11);
243 /** @todo handle this slightly more reasonably, or be really sure
244 * it won't go wrong. */
245 AssertRC(rc);
246
247 ShClX11Destroy(&pCtx->X11);
248 RTCritSectDelete(&pCtx->CritSect);
249
250 RTMemFree(pCtx);
251
252 /* Decrease active connections count. */
253 ASMAtomicDecU32(&g_cShClConnections);
254
255 LogFlowFuncLeaveRC(rc);
256 return rc;
257}
258
259/**
260 * Reports clipboard formats to the host clipboard.
261 */
262int ShClBackendReportFormats(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, SHCLFORMATS fFormats)
263{
264 RT_NOREF(pBackend);
265
266 int rc = ShClX11ReportFormatsToX11Async(&pClient->State.pCtx->X11, fFormats);
267
268 LogFlowFuncLeaveRC(rc);
269 return rc;
270}
271
272/**
273 * Reads data from the host clipboard.
274 *
275 * Schedules a request to the X11 event thread.
276 *
277 * @note We always fail or complete asynchronously.
278 */
279int ShClBackendReadData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat,
280 void *pvData, uint32_t cbData, uint32_t *pcbActual)
281{
282 RT_NOREF(pBackend);
283
284 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
285 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
286 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
287 AssertPtrReturn(pcbActual, VERR_INVALID_POINTER);
288
289 RT_NOREF(pCmdCtx);
290
291 LogFlowFunc(("pClient=%p, uFormat=%#x, pv=%p, cb=%RU32, pcbActual=%p\n",
292 pClient, uFormat, pvData, cbData, pcbActual));
293
294 PSHCLEVENT pEvent;
295 int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
296 if (RT_SUCCESS(rc))
297 {
298 rc = ShClX11ReadDataFromX11Async(&pClient->State.pCtx->X11, uFormat, cbData, pEvent);
299 if (RT_SUCCESS(rc))
300 {
301 PSHCLEVENTPAYLOAD pPayload;
302 rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
303 if (RT_SUCCESS(rc))
304 {
305 if (pPayload)
306 {
307 Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
308 PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
309
310 uint32_t const cbRead = pResp->Read.cbData;
311
312 size_t const cbToCopy = RT_MIN(cbData, cbRead);
313 if (cbToCopy) /* memcpy doesn't like 0 byte inputs. */
314 memcpy(pvData, pResp->Read.pvData, RT_MIN(cbData, cbRead));
315
316 LogRel2(("Shared Clipboard: Read %RU32 bytes host X11 clipboard data\n", cbRead));
317
318 *pcbActual = cbRead;
319
320 RTMemFree(pResp->Read.pvData);
321 pResp->Read.cbData = 0;
322
323 ShClPayloadFree(pPayload);
324 }
325 else /* No payload given; could happen on invalid / not-expected formats. */
326 *pcbActual = 0;
327 }
328 }
329
330 ShClEventRelease(pEvent);
331 }
332
333 if (RT_FAILURE(rc))
334 LogRel(("Shared Clipboard: Error reading host clipboard data from X11, rc=%Rrc\n", rc));
335
336 LogFlowFuncLeaveRC(rc);
337 return rc;
338}
339
340int ShClBackendWriteData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
341 SHCLFORMAT uFormat, void *pvData, uint32_t cbData)
342{
343 RT_NOREF(pBackend, pClient, pCmdCtx, uFormat, pvData, cbData);
344
345 LogFlowFuncEnter();
346
347 /* Nothing to do here yet. */
348
349 LogFlowFuncLeave();
350 return VINF_SUCCESS;
351}
352
353/**
354 * @copydoc SHCLCALLBACKS::pfnReportFormats
355 *
356 * Reports clipboard formats to the guest.
357 */
358static DECLCALLBACK(int) shClSvcX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
359{
360 RT_NOREF(pvUser);
361
362 LogFlowFunc(("pCtx=%p, fFormats=%#x\n", pCtx, fFormats));
363
364 int rc = VINF_SUCCESS;
365 PSHCLCLIENT pClient = pCtx->pClient;
366 AssertPtr(pClient);
367
368 rc = RTCritSectEnter(&pClient->CritSect);
369 if (RT_SUCCESS(rc))
370 {
371 if (ShClSvcIsBackendActive())
372 {
373 /** @todo r=bird: BUGBUG: Revisit this */
374 if (fFormats != VBOX_SHCL_FMT_NONE) /* No formats to report? */
375 {
376 rc = ShClSvcHostReportFormats(pCtx->pClient, fFormats);
377 }
378 }
379
380 RTCritSectLeave(&pClient->CritSect);
381 }
382
383 LogFlowFuncLeaveRC(rc);
384 return rc;
385}
386
387#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
388/**
389 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnCreated
390 *
391 * @thread Service main thread.
392 */
393static DECLCALLBACK(void) shClSvcX11OnTransferCreatedCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
394{
395 LogFlowFuncEnter();
396
397 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
398 AssertPtr(pCtx);
399
400 PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
401 AssertPtr(pTransfer);
402
403 PSHCLCLIENT const pClient = pCtx->pClient;
404 AssertPtr(pClient);
405
406 /*
407 * Set transfer provider.
408 * Those will be registered within ShClSvcTransferInit() when a new transfer gets initialized.
409 */
410
411 /* Set the interface to the local provider by default first. */
412 RT_ZERO(pClient->Transfers.Provider);
413 ShClTransferProviderLocalQueryInterface(&pClient->Transfers.Provider);
414
415 PSHCLTXPROVIDERIFACE pIface = &pClient->Transfers.Provider.Interface;
416
417 switch (ShClTransferGetDir(pTransfer))
418 {
419 case SHCLTRANSFERDIR_FROM_REMOTE: /* Guest -> Host. */
420 {
421 pIface->pfnRootListRead = shClSvcTransferIfaceGHRootListRead;
422
423 pIface->pfnListOpen = shClSvcTransferIfaceGHListOpen;
424 pIface->pfnListClose = shClSvcTransferIfaceGHListClose;
425 pIface->pfnListHdrRead = shClSvcTransferIfaceGHListHdrRead;
426 pIface->pfnListEntryRead = shClSvcTransferIfaceGHListEntryRead;
427
428 pIface->pfnObjOpen = shClSvcTransferIfaceGHObjOpen;
429 pIface->pfnObjClose = shClSvcTransferIfaceGHObjClose;
430 pIface->pfnObjRead = shClSvcTransferIfaceGHObjRead;
431 break;
432 }
433
434 case SHCLTRANSFERDIR_TO_REMOTE: /* Host -> Guest. */
435 {
436 pIface->pfnRootListRead = shClSvcX11TransferIfaceHGRootListRead;
437 break;
438 }
439
440 default:
441 AssertFailed();
442 }
443
444 int rc = ShClTransferSetProvider(pTransfer, &pClient->Transfers.Provider);
445
446 LogFlowFuncLeaveRC(rc);
447}
448
449/**
450 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnInitialized
451 *
452 * This starts the HTTP server if not done yet and registers the transfer with it.
453 *
454 * @thread Service main thread.
455 */
456static DECLCALLBACK(void) shClSvcX11OnTransferInitCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
457{
458 LogFlowFuncEnter();
459
460 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
461 AssertPtr(pCtx);
462
463 PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
464 AssertPtr(pTransfer);
465
466 int rc;
467
468 switch (ShClTransferGetDir(pTransfer))
469 {
470 case SHCLTRANSFERDIR_FROM_REMOTE: /* G->H */
471 {
472# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
473 /* We only need to start the HTTP server when we actually receive data from the remote (host). */
474 rc = ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
475# endif
476 break;
477 }
478
479 case SHCLTRANSFERDIR_TO_REMOTE: /* H->G */
480 {
481 rc = ShClTransferRootListRead(pTransfer); /* Calls shClSvcTransferIfaceHGRootListRead(). */
482 break;
483 }
484
485 default:
486 rc = VERR_NOT_IMPLEMENTED;
487 break;
488 }
489
490 LogFlowFuncLeaveRC(rc);
491}
492
493/**
494 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnDestroy
495 *
496 * This stops the HTTP server if not done yet.
497 *
498 * @thread Service main thread.
499 */
500static DECLCALLBACK(void) shClSvcX11OnTransferDestroyCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
501{
502 LogFlowFuncEnter();
503
504# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
505 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
506 AssertPtr(pCtx);
507
508 PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
509 AssertPtr(pTransfer);
510
511 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
512 ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
513# else
514 RT_NOREF(pCbCtx);
515# endif
516
517 LogFlowFuncLeave();
518}
519
520/**
521 * Unregisters a transfer from a HTTP server.
522 *
523 * This also stops the HTTP server if no active transfers are found anymore.
524 *
525 * @param pCtx Shared clipboard context to unregister transfer for.
526 * @param pTransfer Transfer to unregister.
527 *
528 * @thread Clipboard main thread.
529 */
530static void shClSvcX11HttpTransferUnregister(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
531{
532 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
533 {
534# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
535 if (ShClTransferHttpServerIsInitialized(&pCtx->X11.HttpCtx.HttpServer))
536 {
537 ShClTransferHttpServerUnregisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
538 ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
539 }
540# else
541 RT_NOREF(pCtx);
542# endif
543 }
544
545 //ShClTransferRelease(pTransfer);
546}
547
548/**
549 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnUnregistered
550 *
551 * Unregisters a (now) unregistered transfer from the HTTP server.
552 *
553 * @thread Clipboard main thread.
554 */
555static DECLCALLBACK(void) shClSvcX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
556{
557 RT_NOREF(pTransferCtx);
558 shClSvcX11HttpTransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
559}
560#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
561
562/**
563 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
564 *
565 * Requests clipboard data from the guest.
566 *
567 * @thread Called from X11 event thread.
568 */
569static DECLCALLBACK(int) shClSvcX11RequestDataFromSourceCallback(PSHCLCONTEXT pCtx,
570 SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
571{
572 RT_NOREF(pvUser);
573
574 LogFlowFunc(("pCtx=%p, uFmt=0x%x\n", pCtx, uFmt));
575
576 if (pCtx->fShuttingDown)
577 {
578 /* The shared clipboard is disconnecting. */
579 LogRel(("Shared Clipboard: Host requested guest clipboard data after guest had disconnected\n"));
580 return VERR_WRONG_ORDER;
581 }
582
583 PSHCLCLIENT const pClient = pCtx->pClient;
584 int rc = ShClSvcReadDataFromGuest(pClient, uFmt, ppv, pcb);
585 if (RT_FAILURE(rc))
586 return rc;
587
588 /*
589 * Note: We always return a generic URI list (as HTTP links) here.
590 * As we don't know which Atom target format was requested by the caller, the X11 clipboard codes needs
591 * to decide & transform the list into the actual clipboard Atom target format the caller wanted.
592 */
593#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
594 if (uFmt == VBOX_SHCL_FMT_URI_LIST)
595 {
596 PSHCLTRANSFER pTransfer;
597 rc = ShClSvcTransferCreate(pClient, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
598 NIL_SHCLTRANSFERID /* Creates a new transfer ID */, &pTransfer);
599 if (RT_SUCCESS(rc))
600 {
601 /* Initialize the transfer on the host side. */
602 rc = ShClSvcTransferInit(pClient, pTransfer);
603 if (RT_FAILURE(rc))
604 ShClSvcTransferDestroy(pClient, pTransfer);
605 }
606
607 if (RT_SUCCESS(rc))
608 {
609 /* We have to wait for the guest reporting the transfer as being initialized.
610 * Only then we can start reading stuff. */
611 rc = ShClTransferWaitForStatus(pTransfer, SHCL_TIMEOUT_DEFAULT_MS, SHCLTRANSFERSTATUS_INITIALIZED);
612 if (RT_SUCCESS(rc))
613 {
614 rc = ShClTransferRootListRead(pTransfer);
615 if (RT_SUCCESS(rc))
616 {
617# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
618 /* As soon as we register the transfer with the HTTP server, the transfer needs to have its roots set. */
619 PSHCLHTTPSERVER const pHttpSrv = &pCtx->X11.HttpCtx.HttpServer;
620 rc = ShClTransferHttpServerRegisterTransfer(pHttpSrv, pTransfer);
621 if (RT_SUCCESS(rc))
622 {
623 char *pszURL = ShClTransferHttpServerGetUrlA(pHttpSrv, pTransfer->State.uID);
624 if (pszURL)
625 {
626 *ppv = pszURL;
627 *pcb = strlen(pszURL) + 1 /* Include terminator */;
628
629 LogFlowFunc(("URL is '%s'\n", pszURL));
630
631 /* ppv has ownership of pszURL. */
632
633 rc = VINF_SUCCESS;
634 }
635 else
636 rc = VERR_NO_MEMORY;
637 }
638# else
639 rc = VERR_NOT_SUPPORTED;
640# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
641 }
642 }
643 }
644 }
645#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
646
647 if (RT_FAILURE(rc))
648 LogRel(("Shared Clipboard: Requesting X11 data in format %#x from guest failed with %Rrc\n", uFmt, rc));
649
650 LogFlowFuncLeaveRC(rc);
651 return rc;
652}
653
654#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
655/**
656 * Handles transfer status replies from the guest.
657 */
658int ShClBackendTransferHandleStatusReply(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLSOURCE enmSource, SHCLTRANSFERSTATUS enmStatus, int rcStatus)
659{
660 RT_NOREF(pBackend, pClient, enmSource, rcStatus);
661
662 PSHCLCONTEXT pCtx = pClient->State.pCtx; RT_NOREF(pCtx);
663
664 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host */
665 {
666 switch (enmStatus)
667 {
668 case SHCLTRANSFERSTATUS_INITIALIZED:
669 {
670#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
671 int rc2 = ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
672 if (RT_SUCCESS(rc2))
673 {
674
675 }
676
677 if (RT_FAILURE(rc2))
678 LogRel(("Shared Clipboard: Registering HTTP transfer failed: %Rrc\n", rc2));
679#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
680 break;
681 }
682
683 default:
684 break;
685 }
686 }
687
688 return VINF_SUCCESS;
689}
690
691
692/*********************************************************************************************************************************
693* Provider interface implementation *
694*********************************************************************************************************************************/
695
696/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
697static DECLCALLBACK(int) shClSvcX11TransferIfaceHGRootListRead(PSHCLTXPROVIDERCTX pCtx)
698{
699 LogFlowFuncEnter();
700
701 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
702 AssertPtr(pClient);
703
704 AssertPtr(pClient->State.pCtx);
705 PSHCLX11CTX pX11 = &pClient->State.pCtx->X11;
706
707 PSHCLEVENT pEvent;
708 int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
709 if (RT_SUCCESS(rc))
710 {
711 rc = ShClX11ReadDataFromX11Async(pX11, VBOX_SHCL_FMT_URI_LIST, UINT32_MAX, pEvent);
712 if (RT_SUCCESS(rc))
713 {
714 /* X supplies the data asynchronously, so we need to wait for data to arrive first. */
715 PSHCLEVENTPAYLOAD pPayload;
716 rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
717 if (RT_SUCCESS(rc))
718 {
719 if (pPayload)
720 {
721 Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
722 AssertPtr(pPayload->pvData);
723 PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
724
725 rc = ShClTransferRootsInitFromStringList(pCtx->pTransfer,
726 (char *)pResp->Read.pvData, pResp->Read.cbData + 1 /* Include zero terminator */);
727 if (RT_SUCCESS(rc))
728 LogRel2(("Shared Clipboard: Host reported %RU64 X11 root entries for transfer to guest\n",
729 ShClTransferRootsCount(pCtx->pTransfer)));
730
731 RTMemFree(pResp->Read.pvData);
732 pResp->Read.cbData = 0;
733
734 ShClPayloadFree(pPayload);
735 pPayload = NULL;
736 }
737 else
738 rc = VERR_NO_DATA; /* No payload. */
739 }
740 }
741
742 ShClEventRelease(pEvent);
743 }
744 else
745 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
746
747 LogFlowFuncLeaveRC(rc);
748 return rc;
749}
750#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
751
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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