VirtualBox

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

Last change on this file since 89977 was 89948, checked in by vboxsync, 4 years ago

Attempt to fix build, bugref:10038.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.7 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-x11.cpp 89948 2021-06-29 11:20:08Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Linux host.
4 */
5
6/*
7 * Copyright (C) 2006-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <iprt/assert.h>
24#include <iprt/critsect.h>
25#include <iprt/env.h>
26#include <iprt/mem.h>
27#include <iprt/semaphore.h>
28#include <iprt/string.h>
29#include <iprt/asm.h>
30
31#include <VBox/GuestHost/SharedClipboard.h>
32#include <VBox/GuestHost/SharedClipboard-x11.h>
33#include <VBox/HostServices/VBoxClipboardSvc.h>
34#include <iprt/errcore.h>
35
36#include "VBoxSharedClipboardSvc-internal.h"
37
38/* Number of currently extablished connections. */
39static volatile uint32_t g_cShClConnections;
40
41
42/*********************************************************************************************************************************
43* Structures and Typedefs *
44*********************************************************************************************************************************/
45/**
46 * Global context information used by the host glue for the X11 clipboard backend.
47 */
48struct SHCLCONTEXT
49{
50 /** This mutex is grabbed during any critical operations on the clipboard
51 * which might clash with others. */
52 RTCRITSECT CritSect;
53 /** X11 context data. */
54 SHCLX11CTX X11;
55 /** Pointer to the VBox host client data structure. */
56 PSHCLCLIENT pClient;
57 /** We set this when we start shutting down as a hint not to post any new
58 * requests. */
59 bool fShuttingDown;
60};
61
62
63int ShClBackendInit(void)
64{
65 LogFlowFuncEnter();
66 return VINF_SUCCESS;
67}
68
69void ShClBackendDestroy(void)
70{
71 LogFlowFuncEnter();
72}
73
74/**
75 * @note On the host, we assume that some other application already owns
76 * the clipboard and leave ownership to X11.
77 */
78int ShClBackendConnect(PSHCLCLIENT pClient, bool fHeadless)
79{
80 int rc;
81
82 /* Check if maximum allowed connections count has reached. */
83 if (ASMAtomicIncU32(&g_cShClConnections) > VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX)
84 {
85 ASMAtomicDecU32(&g_cShClConnections);
86 LogRel(("Shared Clipboard: maximum amount for client connections reached\n"));
87 return VERR_OUT_OF_RESOURCES;
88 }
89
90 PSHCLCONTEXT pCtx = (PSHCLCONTEXT)RTMemAllocZ(sizeof(SHCLCONTEXT));
91 if (pCtx)
92 {
93 rc = RTCritSectInit(&pCtx->CritSect);
94 if (RT_SUCCESS(rc))
95 {
96 rc = ShClX11Init(&pCtx->X11, pCtx, fHeadless);
97 if (RT_SUCCESS(rc))
98 {
99 pClient->State.pCtx = pCtx;
100 pCtx->pClient = pClient;
101
102 rc = ShClX11ThreadStart(&pCtx->X11, true /* grab shared clipboard */);
103 if (RT_FAILURE(rc))
104 ShClX11Destroy(&pCtx->X11);
105 }
106
107 if (RT_FAILURE(rc))
108 RTCritSectDelete(&pCtx->CritSect);
109 }
110
111 if (RT_FAILURE(rc))
112 {
113 pClient->State.pCtx = NULL;
114 RTMemFree(pCtx);
115 }
116 }
117 else
118 rc = VERR_NO_MEMORY;
119
120 if (RT_FAILURE(rc))
121 {
122 /* Restore active connections count. */
123 ASMAtomicDecU32(&g_cShClConnections);
124 }
125
126 LogFlowFuncLeaveRC(rc);
127 return rc;
128}
129
130int ShClBackendSync(PSHCLCLIENT pClient)
131{
132 LogFlowFuncEnter();
133
134 /* Tell the guest we have no data in case X11 is not available. If
135 * there is data in the host clipboard it will automatically be sent to
136 * the guest when the clipboard starts up. */
137 return ShClSvcHostReportFormats(pClient, VBOX_SHCL_FMT_NONE);
138}
139
140/*
141 * Shut down the shared clipboard service and "disconnect" the guest.
142 * Note! Host glue code
143 */
144int ShClBackendDisconnect(PSHCLCLIENT pClient)
145{
146 LogFlowFuncEnter();
147
148 PSHCLCONTEXT pCtx = pClient->State.pCtx;
149 AssertPtr(pCtx);
150
151 /* Drop the reference to the client, in case it is still there. This
152 * will cause any outstanding clipboard data requests from X11 to fail
153 * immediately. */
154 pCtx->fShuttingDown = true;
155
156 int rc = ShClX11ThreadStop(&pCtx->X11);
157 /** @todo handle this slightly more reasonably, or be really sure
158 * it won't go wrong. */
159 AssertRC(rc);
160
161 ShClX11Destroy(&pCtx->X11);
162 RTCritSectDelete(&pCtx->CritSect);
163
164 RTMemFree(pCtx);
165
166 /* Decrease active connections count. */
167 ASMAtomicDecU32(&g_cShClConnections);
168
169 LogFlowFuncLeaveRC(rc);
170 return rc;
171}
172
173int ShClBackendFormatAnnounce(PSHCLCLIENT pClient, SHCLFORMATS fFormats)
174{
175 int rc = ShClX11ReportFormatsToX11(&pClient->State.pCtx->X11, fFormats);
176
177 LogFlowFuncLeaveRC(rc);
178 return rc;
179}
180
181/** Structure describing a request for clipoard data from the guest. */
182struct CLIPREADCBREQ
183{
184 /** User-supplied data pointer, based on the request type. */
185 void *pv;
186 /** The size (in bytes) of the the user-supplied pointer in pv. */
187 uint32_t cb;
188 /** The actual size of the data written. */
189 uint32_t *pcbActual;
190 /** The request's event ID. */
191 SHCLEVENTID idEvent;
192};
193
194/**
195 * @note We always fail or complete asynchronously.
196 * @note On success allocates a CLIPREADCBREQ structure which must be
197 * freed in ClipCompleteDataRequestFromX11 when it is called back from
198 * the backend code.
199 */
200int ShClBackendReadData(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat,
201 void *pvData, uint32_t cbData, uint32_t *pcbActual)
202{
203 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
204 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
205 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
206 AssertPtrReturn(pcbActual, VERR_INVALID_POINTER);
207
208 RT_NOREF(pCmdCtx);
209
210 LogFlowFunc(("pClient=%p, uFormat=%02X, pv=%p, cb=%u, pcbActual=%p\n",
211 pClient, uFormat, pvData, cbData, pcbActual));
212
213 int rc = VINF_SUCCESS;
214
215 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
216 if (pReq)
217 {
218 pReq->pv = pvData;
219 pReq->cb = cbData;
220 pReq->pcbActual = pcbActual;
221 const SHCLEVENTID idEvent = ShClEventIdGenerateAndRegister(&pClient->EventSrc);
222 pReq->idEvent = idEvent;
223 if (idEvent != NIL_SHCLEVENTID)
224 {
225 /* Note: ShClX11ReadDataFromX11() will consume pReq on success. */
226 rc = ShClX11ReadDataFromX11(&pClient->State.pCtx->X11, uFormat, pReq);
227 if (RT_SUCCESS(rc))
228 {
229 PSHCLEVENTPAYLOAD pPayload;
230 rc = ShClEventWait(&pClient->EventSrc, idEvent, 30 * 1000, &pPayload);
231 if (RT_SUCCESS(rc))
232 {
233 if (pPayload)
234 {
235 memcpy(pvData, pPayload->pvData, RT_MIN(cbData, pPayload->cbData));
236
237 *pcbActual = (uint32_t)pPayload->cbData;
238
239 ShClPayloadFree(pPayload);
240 }
241 else /* No payload given; could happen on invalid / not-expected formats. */
242 *pcbActual = 0;
243 }
244 }
245
246 ShClEventUnregister(&pClient->EventSrc, idEvent);
247 }
248 else
249 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
250
251 if (RT_FAILURE(rc))
252 RTMemFree(pReq);
253 }
254 else
255 rc = VERR_NO_MEMORY;
256
257 if (RT_FAILURE(rc))
258 LogRel(("Shared Clipboard: Error reading host clipboard data from X11, rc=%Rrc\n", rc));
259
260 LogFlowFuncLeaveRC(rc);
261 return rc;
262}
263
264int ShClBackendWriteData(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData)
265{
266 RT_NOREF(pClient, pCmdCtx, uFormat, pvData, cbData);
267
268 LogFlowFuncEnter();
269
270 /* Nothing to do here yet. */
271
272 LogFlowFuncLeave();
273 return VINF_SUCCESS;
274}
275
276DECLCALLBACK(void) ShClX11ReportFormatsCallback(PSHCLCONTEXT pCtx, uint32_t fFormats)
277{
278 LogFlowFunc(("pCtx=%p, fFormats=%#x\n", pCtx, fFormats));
279
280 int rc = VINF_SUCCESS;
281 PSHCLCLIENT pClient = pCtx->pClient;
282 AssertPtr(pClient);
283
284 rc = RTCritSectEnter(&pClient->CritSect);
285 if (RT_SUCCESS(rc))
286 {
287 /** @todo r=bird: BUGBUG: Revisit this */
288 if (fFormats != VBOX_SHCL_FMT_NONE) /* No formats to report? */
289 {
290 rc = ShClSvcHostReportFormats(pCtx->pClient, fFormats);
291 }
292
293 RTCritSectLeave(&pClient->CritSect);
294 }
295
296 LogFlowFuncLeaveRC(rc);
297}
298
299DECLCALLBACK(void) ShClX11RequestFromX11CompleteCallback(PSHCLCONTEXT pCtx, int rcCompletion,
300 CLIPREADCBREQ *pReq, void *pv, uint32_t cb)
301{
302 AssertPtrReturnVoid(pCtx);
303 AssertPtrReturnVoid(pReq);
304
305 LogFlowFunc(("rcCompletion=%Rrc, pReq=%p, pv=%p, cb=%RU32, idEvent=%RU32\n", rcCompletion, pReq, pv, cb, pReq->idEvent));
306
307 if (pReq->idEvent != NIL_SHCLEVENTID)
308 {
309 int rc2;
310
311 PSHCLEVENTPAYLOAD pPayload = NULL;
312 if ( RT_SUCCESS(rcCompletion)
313 && pv
314 && cb)
315 {
316 rc2 = ShClPayloadAlloc(pReq->idEvent, pv, cb, &pPayload);
317 AssertRC(rc2);
318 }
319
320 rc2 = RTCritSectEnter(&pCtx->pClient->CritSect);
321 if (RT_SUCCESS(rc2))
322 {
323 ShClEventSignal(&pCtx->pClient->EventSrc, pReq->idEvent, pPayload);
324 /* Note: Skip checking if signalling the event is successful, as it could be gone already by now. */
325 RTCritSectLeave(&pCtx->pClient->CritSect);
326 }
327 }
328
329 if (pReq)
330 RTMemFree(pReq);
331
332 LogRel2(("Shared Clipboard: Request for clipboard data from X11 host completed with %Rrc\n", rcCompletion));
333}
334
335DECLCALLBACK(int) ShClX11RequestDataForX11Callback(PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb)
336{
337 LogFlowFunc(("pCtx=%p, uFmt=0x%x\n", pCtx, uFmt));
338
339 if (pCtx->fShuttingDown)
340 {
341 /* The shared clipboard is disconnecting. */
342 LogRel(("Shared Clipboard: Host requested guest clipboard data after guest had disconnected\n"));
343 return VERR_WRONG_ORDER;
344 }
345
346 PSHCLCLIENT pClient = pCtx->pClient;
347 AssertPtr(pClient);
348
349 RTCritSectEnter(&pClient->CritSect);
350
351 int rc = VINF_SUCCESS;
352
353#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
354 /*
355 * Note: We always return a generic URI list here.
356 * As we don't know which Atom target format was requested by the caller, the X11 clipboard codes needs
357 * to decide & transform the list into the actual clipboard Atom target format the caller wanted.
358 */
359 if (uFmt == VBOX_SHCL_FMT_URI_LIST)
360 {
361 PSHCLTRANSFER pTransfer;
362 rc = shClSvcTransferStart(pCtx->pClient,
363 SHCLTRANSFERDIR_FROM_REMOTE, SHCLSOURCE_REMOTE,
364 &pTransfer);
365 if (RT_SUCCESS(rc))
366 {
367
368 }
369 else
370 LogRel(("Shared Clipboard: Initializing read transfer from guest failed with %Rrc\n", rc));
371
372 *ppv = NULL;
373 *pcb = 0;
374
375 rc = VERR_NO_DATA;
376 }
377#endif
378
379 if (RT_SUCCESS(rc))
380 {
381 /* Request data from the guest. */
382 SHCLEVENTID idEvent;
383 rc = ShClSvcGuestDataRequest(pCtx->pClient, uFmt, &idEvent);
384 if (RT_SUCCESS(rc))
385 {
386 RTCritSectLeave(&pClient->CritSect);
387
388 PSHCLEVENTPAYLOAD pPayload;
389 rc = ShClEventWait(&pCtx->pClient->EventSrc, idEvent, 30 * 1000, &pPayload);
390 if (RT_SUCCESS(rc))
391 {
392 if ( !pPayload
393 || !pPayload->cbData)
394 {
395 rc = VERR_NO_DATA;
396 }
397 else
398 {
399 *ppv = pPayload->pvData;
400 *pcb = pPayload->cbData;
401 }
402 }
403
404 RTCritSectEnter(&pClient->CritSect);
405
406 ShClEventRelease(&pCtx->pClient->EventSrc, idEvent);
407 ShClEventUnregister(&pCtx->pClient->EventSrc, idEvent);
408 }
409 }
410
411 RTCritSectLeave(&pClient->CritSect);
412
413 if (RT_FAILURE(rc))
414 LogRel(("Shared Clipboard: Requesting data in format %#x for X11 host failed with %Rrc\n", uFmt, rc));
415
416 LogFlowFuncLeaveRC(rc);
417 return rc;
418}
419
420#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
421
422int ShClBackendTransferCreate(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
423{
424#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
425 return ShClHttpTransferRegister(&pClient->State.pCtx->X11.HttpCtx, pTransfer);
426#else
427 RT_NOREF(pClient, pTransfer);
428#endif
429 return VERR_NOT_IMPLEMENTED;
430}
431
432int ShClBackendTransferDestroy(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
433{
434#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP
435 return ShClHttpTransferUnregister(&pClient->State.pCtx->X11.HttpCtx, pTransfer);
436#else
437 RT_NOREF(pClient, pTransfer);
438#endif
439
440 return VINF_SUCCESS;
441}
442
443int ShClBackendTransferGetRoots(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
444{
445 LogFlowFuncEnter();
446
447 int rc;
448
449 SHCLEVENTID idEvent = ShClEventIdGenerateAndRegister(&pClient->EventSrc);
450 if (idEvent != NIL_SHCLEVENTID)
451 {
452 CLIPREADCBREQ *pReq = (CLIPREADCBREQ *)RTMemAllocZ(sizeof(CLIPREADCBREQ));
453 if (pReq)
454 {
455 pReq->idEvent = idEvent;
456
457 rc = ShClX11ReadDataFromX11(&pClient->State.pCtx->X11, VBOX_SHCL_FMT_URI_LIST, pReq);
458 if (RT_SUCCESS(rc))
459 {
460 /* X supplies the data asynchronously, so we need to wait for data to arrive first. */
461 PSHCLEVENTPAYLOAD pPayload;
462 rc = ShClEventWait(&pClient->EventSrc, idEvent, 30 * 1000, &pPayload);
463 if (RT_SUCCESS(rc))
464 {
465 rc = ShClTransferRootsSet(pTransfer,
466 (char *)pPayload->pvData, pPayload->cbData + 1 /* Include termination */);
467 }
468 }
469 }
470 else
471 rc = VERR_NO_MEMORY;
472
473 ShClEventUnregister(&pClient->EventSrc, idEvent);
474 }
475 else
476 rc = VERR_SHCLPB_MAX_EVENTS_REACHED;
477
478 LogFlowFuncLeaveRC(rc);
479 return rc;
480}
481#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
482
Note: See TracBrowser for help on using the repository browser.

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