VirtualBox

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

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

Shared Clipboard: Removed ShClBackendTransferHGRootListRead(), not needed. ​​bugref:9437

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 22.0 KB
 
1/* $Id: VBoxSharedClipboardSvc-x11.cpp 100370 2023-07-05 07:14:28Z 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) shClSvcX11OnTransferInitCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx);
91static DECLCALLBACK(void) shClSvcX11OnTransferDestroyCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx);
92static DECLCALLBACK(void) shClSvcX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx);
93#endif
94
95
96int ShClBackendInit(PSHCLBACKEND pBackend, VBOXHGCMSVCFNTABLE *pTable)
97{
98 RT_NOREF(pBackend);
99
100 LogFlowFuncEnter();
101
102 /* Override the connection limit. */
103 for (uintptr_t i = 0; i < RT_ELEMENTS(pTable->acMaxClients); i++)
104 pTable->acMaxClients[i] = RT_MIN(VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX, pTable->acMaxClients[i]);
105
106 RT_ZERO(pBackend->Callbacks);
107 /* Use internal callbacks by default. */
108 pBackend->Callbacks.pfnReportFormats = shClSvcX11ReportFormatsCallback;
109 pBackend->Callbacks.pfnOnRequestDataFromSource = shClSvcX11RequestDataFromSourceCallback;
110
111 return VINF_SUCCESS;
112}
113
114void ShClBackendDestroy(PSHCLBACKEND pBackend)
115{
116 RT_NOREF(pBackend);
117
118 LogFlowFuncEnter();
119}
120
121void ShClBackendSetCallbacks(PSHCLBACKEND pBackend, PSHCLCALLBACKS pCallbacks)
122{
123#define SET_FN_IF_NOT_NULL(a_Fn) \
124 if (pCallbacks->pfn##a_Fn) \
125 pBackend->Callbacks.pfn##a_Fn = pCallbacks->pfn##a_Fn;
126
127 SET_FN_IF_NOT_NULL(ReportFormats);
128 SET_FN_IF_NOT_NULL(OnRequestDataFromSource);
129
130#undef SET_FN_IF_NOT_NULL
131}
132
133/**
134 * @note On the host, we assume that some other application already owns
135 * the clipboard and leave ownership to X11.
136 */
137int ShClBackendConnect(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, bool fHeadless)
138{
139 int rc;
140
141 /* Check if maximum allowed connections count has reached. */
142 if (ASMAtomicIncU32(&g_cShClConnections) > VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX)
143 {
144 ASMAtomicDecU32(&g_cShClConnections);
145 LogRel(("Shared Clipboard: maximum amount for client connections reached\n"));
146 return VERR_OUT_OF_RESOURCES;
147 }
148
149 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
150 if (pCtx)
151 {
152 rc = RTCritSectInit(&pCtx->CritSect);
153 if (RT_SUCCESS(rc))
154 {
155 rc = ShClX11Init(&pCtx->X11, &pBackend->Callbacks, pCtx, fHeadless);
156 if (RT_SUCCESS(rc))
157 {
158 pClient->State.pCtx = pCtx;
159 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 */
177
178 rc = ShClX11ThreadStart(&pCtx->X11, true /* grab shared clipboard */);
179 if (RT_FAILURE(rc))
180 ShClX11Destroy(&pCtx->X11);
181 }
182
183 if (RT_FAILURE(rc))
184 RTCritSectDelete(&pCtx->CritSect);
185 }
186
187 if (RT_FAILURE(rc))
188 {
189 pClient->State.pCtx = NULL;
190 RTMemFree(pCtx);
191 }
192 }
193 else
194 rc = VERR_NO_MEMORY;
195
196 if (RT_FAILURE(rc))
197 {
198 /* Restore active connections count. */
199 ASMAtomicDecU32(&g_cShClConnections);
200 }
201
202 LogFlowFuncLeaveRC(rc);
203 return rc;
204}
205
206int ShClBackendSync(PSHCLBACKEND pBackend, PSHCLCLIENT pClient)
207{
208 RT_NOREF(pBackend);
209
210 LogFlowFuncEnter();
211
212 /* Tell the guest we have no data in case X11 is not available. If
213 * there is data in the host clipboard it will automatically be sent to
214 * the guest when the clipboard starts up. */
215 if (ShClSvcIsBackendActive())
216 return ShClSvcHostReportFormats(pClient, VBOX_SHCL_FMT_NONE);
217 return VINF_SUCCESS;
218}
219
220/**
221 * Shuts down the shared clipboard service and "disconnect" the guest.
222 * Note! Host glue code
223 */
224int ShClBackendDisconnect(PSHCLBACKEND pBackend, PSHCLCLIENT pClient)
225{
226 RT_NOREF(pBackend);
227
228 LogFlowFuncEnter();
229
230 PSHCLCONTEXT pCtx = pClient->State.pCtx;
231 AssertPtr(pCtx);
232
233 /* Drop the reference to the client, in case it is still there. This
234 * will cause any outstanding clipboard data requests from X11 to fail
235 * immediately. */
236 pCtx->fShuttingDown = true;
237
238 int rc = ShClX11ThreadStop(&pCtx->X11);
239 /** @todo handle this slightly more reasonably, or be really sure
240 * it won't go wrong. */
241 AssertRC(rc);
242
243 ShClX11Destroy(&pCtx->X11);
244 RTCritSectDelete(&pCtx->CritSect);
245
246 RTMemFree(pCtx);
247
248 /* Decrease active connections count. */
249 ASMAtomicDecU32(&g_cShClConnections);
250
251 LogFlowFuncLeaveRC(rc);
252 return rc;
253}
254
255/**
256 * Reports clipboard formats to the host clipboard.
257 */
258int ShClBackendReportFormats(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, SHCLFORMATS fFormats)
259{
260 RT_NOREF(pBackend);
261
262 int rc = ShClX11ReportFormatsToX11Async(&pClient->State.pCtx->X11, fFormats);
263
264 LogFlowFuncLeaveRC(rc);
265 return rc;
266}
267
268/**
269 * Reads data from the host clipboard.
270 *
271 * Schedules a request to the X11 event thread.
272 *
273 * @note We always fail or complete asynchronously.
274 */
275int ShClBackendReadData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat,
276 void *pvData, uint32_t cbData, uint32_t *pcbActual)
277{
278 RT_NOREF(pBackend);
279
280 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
281 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
282 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
283 AssertPtrReturn(pcbActual, VERR_INVALID_POINTER);
284
285 RT_NOREF(pCmdCtx);
286
287 LogFlowFunc(("pClient=%p, uFormat=%#x, pv=%p, cb=%RU32, pcbActual=%p\n",
288 pClient, uFormat, pvData, cbData, pcbActual));
289
290 PSHCLEVENT pEvent;
291 int rc = ShClEventSourceGenerateAndRegisterEvent(&pClient->EventSrc, &pEvent);
292 if (RT_SUCCESS(rc))
293 {
294 rc = ShClX11ReadDataFromX11Async(&pClient->State.pCtx->X11, uFormat, cbData, pEvent);
295 if (RT_SUCCESS(rc))
296 {
297 PSHCLEVENTPAYLOAD pPayload;
298 rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
299 if (RT_SUCCESS(rc))
300 {
301 if (pPayload)
302 {
303 Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
304 PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
305
306 uint32_t const cbRead = pResp->Read.cbData;
307
308 size_t const cbToCopy = RT_MIN(cbData, cbRead);
309 if (cbToCopy) /* memcpy doesn't like 0 byte inputs. */
310 memcpy(pvData, pResp->Read.pvData, RT_MIN(cbData, cbRead));
311
312 LogRel2(("Shared Clipboard: Read %RU32 bytes host X11 clipboard data\n", cbRead));
313
314 *pcbActual = cbRead;
315
316 RTMemFree(pResp->Read.pvData);
317 pResp->Read.cbData = 0;
318
319 ShClPayloadFree(pPayload);
320 }
321 else /* No payload given; could happen on invalid / not-expected formats. */
322 *pcbActual = 0;
323 }
324 }
325
326 ShClEventRelease(pEvent);
327 }
328
329 if (RT_FAILURE(rc))
330 LogRel(("Shared Clipboard: Error reading host clipboard data from X11, rc=%Rrc\n", rc));
331
332 LogFlowFuncLeaveRC(rc);
333 return rc;
334}
335
336int ShClBackendWriteData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx,
337 SHCLFORMAT uFormat, void *pvData, uint32_t cbData)
338{
339 RT_NOREF(pBackend, pClient, pCmdCtx, uFormat, pvData, cbData);
340
341 LogFlowFuncEnter();
342
343 /* Nothing to do here yet. */
344
345 LogFlowFuncLeave();
346 return VINF_SUCCESS;
347}
348
349/**
350 * @copydoc SHCLCALLBACKS::pfnReportFormats
351 *
352 * Reports clipboard formats to the guest.
353 */
354static DECLCALLBACK(int) shClSvcX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats, void *pvUser)
355{
356 RT_NOREF(pvUser);
357
358 LogFlowFunc(("pCtx=%p, fFormats=%#x\n", pCtx, fFormats));
359
360 int rc = VINF_SUCCESS;
361 PSHCLCLIENT pClient = pCtx->pClient;
362 AssertPtr(pClient);
363
364 rc = RTCritSectEnter(&pClient->CritSect);
365 if (RT_SUCCESS(rc))
366 {
367 if (ShClSvcIsBackendActive())
368 {
369 /** @todo r=bird: BUGBUG: Revisit this */
370 if (fFormats != VBOX_SHCL_FMT_NONE) /* No formats to report? */
371 {
372 rc = ShClSvcHostReportFormats(pCtx->pClient, fFormats);
373 }
374 }
375
376 RTCritSectLeave(&pClient->CritSect);
377 }
378
379 LogFlowFuncLeaveRC(rc);
380 return rc;
381}
382
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 LogFlowFuncEnter();
396
397 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
398 AssertPtr(pCtx);
399
400 PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
401 AssertPtr(pTransfer);
402
403 switch (ShClTransferGetDir(pTransfer))
404 {
405 case SHCLTRANSFERDIR_FROM_REMOTE: /* G->H */
406 {
407# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
408 /* We only need to start the HTTP server when we actually receive data from the remote (host). */
409 ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
410# endif
411 break;
412 }
413
414 case SHCLTRANSFERDIR_TO_REMOTE: /* H->G */
415 {
416 PSHCLEVENT pEvent;
417 int rc = ShClEventSourceGenerateAndRegisterEvent(&pCtx->pClient->EventSrc, &pEvent);
418 if (RT_SUCCESS(rc))
419 {
420 rc = ShClX11ReadDataFromX11Async(&pCtx->X11, VBOX_SHCL_FMT_URI_LIST, UINT32_MAX, pEvent);
421 if (RT_SUCCESS(rc))
422 {
423 /* X supplies the data asynchronously, so we need to wait for data to arrive first. */
424 PSHCLEVENTPAYLOAD pPayload;
425 rc = ShClEventWait(pEvent, SHCL_TIMEOUT_DEFAULT_MS, &pPayload);
426 if (RT_SUCCESS(rc))
427 {
428 if (pPayload)
429 {
430 Assert(pPayload->cbData == sizeof(SHCLX11RESPONSE));
431 AssertPtr(pPayload->pvData);
432 PSHCLX11RESPONSE pResp = (PSHCLX11RESPONSE)pPayload->pvData;
433
434 rc = ShClTransferRootsInitFromStringList(pTransfer,
435 (char *)pResp->Read.pvData, pResp->Read.cbData + 1 /* Include zero terminator */);
436 if (RT_SUCCESS(rc))
437 LogRel2(("Shared Clipboard: Host reported %RU64 X11 root entries for transfer to guest\n", ShClTransferRootsCount(pTransfer)));
438
439 RTMemFree(pResp->Read.pvData);
440 pResp->Read.cbData = 0;
441
442 ShClPayloadFree(pPayload);
443 pPayload = NULL;
444 }
445 else
446 rc = VERR_NO_DATA; /* No payload. */
447 }
448 }
449
450 ShClEventRelease(pEvent);
451 }
452 else
453 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
454 break;
455 }
456
457 default:
458 break;
459 }
460
461 LogFlowFuncLeave();
462}
463
464/**
465 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnDestroy
466 *
467 * This stops the HTTP server if not done yet.
468 *
469 * @thread Service main thread.
470 */
471static DECLCALLBACK(void) shClSvcX11OnTransferDestroyCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx)
472{
473 LogFlowFuncEnter();
474
475# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
476 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)pCbCtx->pvUser;
477 AssertPtr(pCtx);
478
479 PSHCLTRANSFER pTransfer = pCbCtx->pTransfer;
480 AssertPtr(pTransfer);
481
482 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
483 ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
484# else
485 RT_NOREF(pCbCtx);
486# endif
487
488 LogFlowFuncLeave();
489}
490
491/**
492 * Unregisters a transfer from a HTTP server.
493 *
494 * This also stops the HTTP server if no active transfers are found anymore.
495 *
496 * @param pCtx Shared clipboard context to unregister transfer for.
497 * @param pTransfer Transfer to unregister.
498 *
499 * @thread Clipboard main thread.
500 */
501static void shClSvcX11HttpTransferUnregister(PSHCLCONTEXT pCtx, PSHCLTRANSFER pTransfer)
502{
503 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE)
504 {
505# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
506 if (ShClTransferHttpServerIsInitialized(&pCtx->X11.HttpCtx.HttpServer))
507 {
508 ShClTransferHttpServerUnregisterTransfer(&pCtx->X11.HttpCtx.HttpServer, pTransfer);
509 ShClTransferHttpServerMaybeStop(&pCtx->X11.HttpCtx);
510 }
511# else
512 RT_NOREF(pCtx);
513# endif
514 }
515
516 //ShClTransferRelease(pTransfer);
517}
518
519/**
520 * @copydoc SHCLTRANSFERCALLBACKS::pfnOnUnregistered
521 *
522 * Unregisters a (now) unregistered transfer from the HTTP server.
523 *
524 * @thread Clipboard main thread.
525 */
526static DECLCALLBACK(void) shClSvcX11OnTransferUnregisteredCallback(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)
527{
528 RT_NOREF(pTransferCtx);
529 shClSvcX11HttpTransferUnregister((PSHCLCONTEXT)pCbCtx->pvUser, pCbCtx->pTransfer);
530}
531#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
532
533/**
534 * @copydoc SHCLCALLBACKS::pfnOnRequestDataFromSource
535 *
536 * Requests clipboard data from the guest.
537 *
538 * @thread Called from X11 event thread.
539 */
540static DECLCALLBACK(int) shClSvcX11RequestDataFromSourceCallback(PSHCLCONTEXT pCtx,
541 SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)
542{
543 RT_NOREF(pvUser);
544
545 LogFlowFunc(("pCtx=%p, uFmt=0x%x\n", pCtx, uFmt));
546
547 if (pCtx->fShuttingDown)
548 {
549 /* The shared clipboard is disconnecting. */
550 LogRel(("Shared Clipboard: Host requested guest clipboard data after guest had disconnected\n"));
551 return VERR_WRONG_ORDER;
552 }
553
554 PSHCLCLIENT const pClient = pCtx->pClient;
555 int rc = ShClSvcReadDataFromGuest(pClient, uFmt, ppv, pcb);
556 if (RT_FAILURE(rc))
557 return rc;
558
559 /*
560 * Note: We always return a generic URI list (as HTTP links) here.
561 * As we don't know which Atom target format was requested by the caller, the X11 clipboard codes needs
562 * to decide & transform the list into the actual clipboard Atom target format the caller wanted.
563 */
564#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
565 if (uFmt == VBOX_SHCL_FMT_URI_LIST)
566 {
567 PSHCLTRANSFER pTransfer;
568 rc = ShClSvcTransferCreate(pClient, SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
569 NIL_SHCLTRANSFERID /* Creates a new transfer ID */, &pTransfer);
570 if (RT_SUCCESS(rc))
571 {
572 /* Initialize the transfer on the host side. */
573 rc = ShClSvcTransferInit(pClient, pTransfer);
574 if (RT_FAILURE(rc))
575 ShClSvcTransferDestroy(pClient, pTransfer);
576 }
577
578 if (RT_SUCCESS(rc))
579 {
580 /* We have to wait for the guest reporting the transfer as being initialized.
581 * Only then we can start reading stuff. */
582 rc = ShClTransferWaitForStatus(pTransfer, SHCL_TIMEOUT_DEFAULT_MS, SHCLTRANSFERSTATUS_INITIALIZED);
583 if (RT_SUCCESS(rc))
584 {
585 rc = ShClTransferRootListRead(pTransfer);
586 if (RT_SUCCESS(rc))
587 {
588# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
589 /* As soon as we register the transfer with the HTTP server, the transfer needs to have its roots set. */
590 PSHCLHTTPSERVER const pHttpSrv = &pCtx->X11.HttpCtx.HttpServer;
591 rc = ShClTransferHttpServerRegisterTransfer(pHttpSrv, pTransfer);
592 if (RT_SUCCESS(rc))
593 {
594 char *pszURL = ShClTransferHttpServerGetUrlA(pHttpSrv, pTransfer->State.uID);
595 if (pszURL)
596 {
597 *ppv = pszURL;
598 *pcb = strlen(pszURL) + 1 /* Include terminator */;
599
600 LogFlowFunc(("URL is '%s'\n", pszURL));
601
602 /* ppv has ownership of pszURL. */
603
604 rc = VINF_SUCCESS;
605 }
606 else
607 rc = VERR_NO_MEMORY;
608 }
609# else
610 rc = VERR_NOT_SUPPORTED;
611# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
612 }
613 }
614 }
615 }
616#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
617
618 if (RT_FAILURE(rc))
619 LogRel(("Shared Clipboard: Requesting X11 data in format %#x from guest failed with %Rrc\n", uFmt, rc));
620
621 LogFlowFuncLeaveRC(rc);
622 return rc;
623}
624
625#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
626/**
627 * Handles transfer status replies from the guest.
628 */
629int ShClBackendTransferHandleStatusReply(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLSOURCE enmSource, SHCLTRANSFERSTATUS enmStatus, int rcStatus)
630{
631 RT_NOREF(pBackend, pClient, enmSource, rcStatus);
632
633 PSHCLCONTEXT pCtx = pClient->State.pCtx; RT_NOREF(pCtx);
634
635 if (ShClTransferGetDir(pTransfer) == SHCLTRANSFERDIR_FROM_REMOTE) /* Guest -> Host */
636 {
637 switch (enmStatus)
638 {
639 case SHCLTRANSFERSTATUS_INITIALIZED:
640 {
641#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
642 int rc2 = ShClTransferHttpServerMaybeStart(&pCtx->X11.HttpCtx);
643 if (RT_SUCCESS(rc2))
644 {
645
646 }
647
648 if (RT_FAILURE(rc2))
649 LogRel(("Shared Clipboard: Registering HTTP transfer failed: %Rrc\n", rc2));
650#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */
651 break;
652 }
653
654 default:
655 break;
656 }
657 }
658
659 return VINF_SUCCESS;
660}
661#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
662
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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