diff options
Diffstat (limited to '')
-rw-r--r-- | src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h b/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h new file mode 100644 index 00000000..add48a0c --- /dev/null +++ b/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-internal.h @@ -0,0 +1,531 @@ +/* $Id: VBoxSharedClipboardSvc-internal.h $ */ +/** @file + * Shared Clipboard Service - Internal header. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#ifndef VBOX_INCLUDED_SRC_SharedClipboard_VBoxSharedClipboardSvc_internal_h +#define VBOX_INCLUDED_SRC_SharedClipboard_VBoxSharedClipboardSvc_internal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <algorithm> +#include <list> +#include <map> + +#include <iprt/cpp/list.h> /* For RTCList. */ +#include <iprt/list.h> +#include <iprt/semaphore.h> + +#include <VBox/hgcmsvc.h> +#include <VBox/log.h> + +#include <VBox/HostServices/Service.h> +#include <VBox/GuestHost/SharedClipboard.h> +#include <VBox/GuestHost/SharedClipboard-transfers.h> + +using namespace HGCM; + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +struct SHCLCLIENTSTATE; +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +/** + * A queued message for the guest. + */ +typedef struct _SHCLCLIENTMSG +{ + /** The queue list entry. */ + RTLISTNODE ListEntry; + /** Stored message ID (VBOX_SHCL_HOST_MSG_XXX). */ + uint32_t idMsg; + /** Context ID. */ + uint64_t idCtx; + /** Number of stored parameters in aParms. */ + uint32_t cParms; + /** HGCM parameters. */ + RT_FLEXIBLE_ARRAY_EXTENSION + VBOXHGCMSVCPARM aParms[RT_FLEXIBLE_ARRAY]; +} SHCLCLIENTMSG; +/** Pointer to a queue message for the guest. */ +typedef SHCLCLIENTMSG *PSHCLCLIENTMSG; + +typedef struct SHCLCLIENTTRANSFERSTATE +{ + /** Directory of the transfer to start. */ + SHCLTRANSFERDIR enmTransferDir; +} SHCLCLIENTTRANSFERSTATE, *PSHCLCLIENTTRANSFERSTATE; + +/** + * Structure for holding a single POD (plain old data) transfer. + * + * This mostly is plain text, but also can be stuff like bitmap (BMP) or other binary data. + */ +typedef struct SHCLCLIENTPODSTATE +{ + /** POD transfer direction. */ + SHCLTRANSFERDIR enmDir; + /** Format of the data to be read / written. */ + SHCLFORMAT uFormat; + /** How much data (in bytes) to read/write for the current operation. */ + uint64_t cbToReadWriteTotal; + /** How much data (in bytes) already has been read/written for the current operation. */ + uint64_t cbReadWritten; + /** Timestamp (in ms) of Last read/write operation. */ + uint64_t tsLastReadWrittenMs; +} SHCLCLIENTPODSTATE, *PSHCLCLIENTPODSTATE; + +/** @name SHCLCLIENTSTATE_FLAGS_XXX + * @note Part of saved state! + * @{ */ +/** No Shared Clipboard client flags defined. */ +#define SHCLCLIENTSTATE_FLAGS_NONE 0 +/** Client has a guest read operation active. Currently unused. */ +#define SHCLCLIENTSTATE_FLAGS_READ_ACTIVE RT_BIT(0) +/** Client has a guest write operation active. Currently unused. */ +#define SHCLCLIENTSTATE_FLAGS_WRITE_ACTIVE RT_BIT(1) +/** @} */ + +/** + * Structure needed to support backwards compatbility for old(er) Guest Additions (< 6.1), + * which did not know the context ID concept then. + */ +typedef struct SHCLCLIENTLEGACYCID +{ + /** List node. */ + RTLISTNODE Node; + /** The actual context ID. */ + uint64_t uCID; + /** Not used yet; useful to have it in the saved state though. */ + uint32_t enmType; + /** @todo Add an union here as soon as we utilize \a enmType. */ + SHCLFORMAT uFormat; +} SHCLCLIENTLEGACYCID; +/** Pointer to a SHCLCLIENTLEGACYCID struct. */ +typedef SHCLCLIENTLEGACYCID *PSHCLCLIENTLEGACYCID; + +/** + * Structure for keeping legacy state, required for keeping backwards compatibility + * to old(er) Guest Additions. + */ +typedef struct SHCLCLIENTLEGACYSTATE +{ + /** List of context IDs (of type SHCLCLIENTLEGACYCID) for older Guest Additions which (< 6.1) + * which did not know the concept of context IDs. */ + RTLISTANCHOR lstCID; + /** Number of context IDs currently in \a lstCID. */ + uint16_t cCID; +} SHCLCLIENTLEGACYSTATE; + +/** + * Structure for keeping generic client state data within the Shared Clipboard host service. + * This structure needs to be serializable by SSM (must be a POD type). + */ +typedef struct SHCLCLIENTSTATE +{ + struct SHCLCLIENTSTATE *pNext; + struct SHCLCLIENTSTATE *pPrev; + + /** Backend-dependent opaque context structure. + * This contains data only known to a certain backend implementation. + * Optional and can be NULL. */ + SHCLCONTEXT *pCtx; + /** The client's HGCM ID. Not related to the session ID below! */ + uint32_t uClientID; + /** The client's session ID. */ + SHCLSESSIONID uSessionID; + /** Guest feature flags, VBOX_SHCL_GF_0_XXX. */ + uint64_t fGuestFeatures0; + /** Guest feature flags, VBOX_SHCL_GF_1_XXX. */ + uint64_t fGuestFeatures1; + /** Chunk size to use for data transfers. */ + uint32_t cbChunkSize; + /** Where the transfer sources its data from. */ + SHCLSOURCE enmSource; + /** Client state flags of type SHCLCLIENTSTATE_FLAGS_. */ + uint32_t fFlags; + /** POD (plain old data) state. */ + SHCLCLIENTPODSTATE POD; + /** The client's transfers state. */ + SHCLCLIENTTRANSFERSTATE Transfers; +} SHCLCLIENTSTATE, *PSHCLCLIENTSTATE; + +typedef struct _SHCLCLIENTCMDCTX +{ + uint64_t uContextID; +} SHCLCLIENTCMDCTX, *PSHCLCLIENTCMDCTX; + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** + * Structure for keeping transfer-related data per HGCM client. + */ +typedef struct _SHCLIENTTRANSFERS +{ + /** Transfer context. */ + SHCLTRANSFERCTX Ctx; +} SHCLIENTTRANSFERS, *PSHCLIENTTRANSFERS; +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +/** Prototypes for the Shared Clipboard backend. */ +struct SHCLBACKEND; +typedef SHCLBACKEND *PSHCLBACKEND; + +/** + * Structure for keeping data per (connected) HGCM client. + */ +typedef struct _SHCLCLIENT +{ + /** Pointer to associated backend, if any. + * Might be NULL if not being used. */ + PSHCLBACKEND pBackend; + /** General client state data. */ + SHCLCLIENTSTATE State; + /** The critical section protecting the queue, event source and whatnot. */ + RTCRITSECT CritSect; + /** The client's message queue (SHCLCLIENTMSG). */ + RTLISTANCHOR MsgQueue; + /** Number of allocated messages (updated atomically, not under critsect). */ + uint32_t volatile cMsgAllocated; + /** Legacy cruft we have to keep to support old(er) Guest Additions. */ + SHCLCLIENTLEGACYSTATE Legacy; + /** The client's own event source. + * Needed for events which are not bound to a specific transfer. */ + SHCLEVENTSOURCE EventSrc; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + SHCLIENTTRANSFERS Transfers; +#endif + /** Structure for keeping the client's pending (deferred return) state. + * A client is in a deferred state when it asks for the next HGCM message, + * but the service can't provide it yet. That way a client will block (on the guest side, does not return) + * until the service can complete the call. */ + struct + { + /** The client's HGCM call handle. Needed for completing a deferred call. */ + VBOXHGCMCALLHANDLE hHandle; + /** Message type (function number) to use when completing the deferred call. + * A non-0 value means the client is in pending mode. */ + uint32_t uType; + /** Parameter count to use when completing the deferred call. */ + uint32_t cParms; + /** Parameters to use when completing the deferred call. */ + PVBOXHGCMSVCPARM paParms; + } Pending; +} SHCLCLIENT, *PSHCLCLIENT; + +/** + * Structure for keeping a single event source map entry. + * Currently empty. + */ +typedef struct _SHCLEVENTSOURCEMAPENTRY +{ +} SHCLEVENTSOURCEMAPENTRY; + +/** Map holding information about connected HGCM clients. Key is the (unique) HGCM client ID. + * The value is a weak pointer to PSHCLCLIENT, which is owned by HGCM. */ +typedef std::map<uint32_t, PSHCLCLIENT> ClipboardClientMap; + +/** Map holding information about event sources. Key is the (unique) event source ID. */ +typedef std::map<SHCLEVENTSOURCEID, SHCLEVENTSOURCEMAPENTRY> ClipboardEventSourceMap; + +/** Simple queue (list) which holds deferred (waiting) clients. */ +typedef std::list<uint32_t> ClipboardClientQueue; + +/** + * Structure for keeping the Shared Clipboard service extension state. + * + * A service extension is optional, and can be installed by a host component + * to communicate with the Shared Clipboard host service. + */ +typedef struct _SHCLEXTSTATE +{ + /** Pointer to the actual service extension handle. */ + PFNHGCMSVCEXT pfnExtension; + /** Opaque pointer to extension-provided data. Don't touch. */ + void *pvExtension; + /** The HGCM client ID currently assigned to this service extension. + * At the moment only one HGCM client can be assigned per extension. */ + uint32_t uClientID; + /** Whether the host service is reading clipboard data currently. */ + bool fReadingData; + /** Whether the service extension has sent the clipboard formats while + * the the host service is reading clipboard data from it. */ + bool fDelayedAnnouncement; + /** The actual clipboard formats announced while the host service + * is reading clipboard data from the extension. */ + uint32_t fDelayedFormats; +} SHCLEXTSTATE, *PSHCLEXTSTATE; + +extern SHCLEXTSTATE g_ExtState; + +int shClSvcSetSource(PSHCLCLIENT pClient, SHCLSOURCE enmSource); + +void shClSvcMsgQueueReset(PSHCLCLIENT pClient); +PSHCLCLIENTMSG shClSvcMsgAlloc(PSHCLCLIENT pClient, uint32_t uMsg, uint32_t cParms); +void shClSvcMsgFree(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg); +void shClSvcMsgAdd(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg, bool fAppend); +int shClSvcMsgAddAndWakeupClient(PSHCLCLIENT pClient, PSHCLCLIENTMSG pMsg); + +int shClSvcClientInit(PSHCLCLIENT pClient, uint32_t uClientID); +void shClSvcClientDestroy(PSHCLCLIENT pClient); +void shClSvcClientLock(PSHCLCLIENT pClient); +void shClSvcClientUnlock(PSHCLCLIENT pClient); +void shClSvcClientReset(PSHCLCLIENT pClient); + +int shClSvcClientStateInit(PSHCLCLIENTSTATE pClientState, uint32_t uClientID); +int shClSvcClientStateDestroy(PSHCLCLIENTSTATE pClientState); +void shclSvcClientStateReset(PSHCLCLIENTSTATE pClientState); + +int shClSvcClientWakeup(PSHCLCLIENT pClient); + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +int shClSvcTransferModeSet(uint32_t fMode); +int shClSvcTransferStart(PSHCLCLIENT pClient, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, PSHCLTRANSFER *ppTransfer); +int shClSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer); +bool shClSvcTransferMsgIsAllowed(uint32_t uMode, uint32_t uMsg); +void shClSvcClientTransfersReset(PSHCLCLIENT pClient); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +/** @name Service functions, accessible by the backends. + * Locking is between the (host) service thread and the platform-dependent (window) thread. + * @{ + */ +int ShClSvcGuestDataRequest(PSHCLCLIENT pClient, SHCLFORMATS fFormats, PSHCLEVENT *ppEvent); +int ShClSvcGuestDataSignal(PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData); +int ShClSvcHostReportFormats(PSHCLCLIENT pClient, SHCLFORMATS fFormats); +PSHCLBACKEND ShClSvcGetBackend(void); +uint32_t ShClSvcGetMode(void); +bool ShClSvcGetHeadless(void); +bool ShClSvcLock(void); +void ShClSvcUnlock(void); + +/** + * Checks if the backend is active (@c true), or if VRDE is in control of + * the host side. + */ +DECLINLINE(bool) ShClSvcIsBackendActive(void) +{ + return g_ExtState.pfnExtension == NULL; +} +/** @} */ + +/** @name Platform-dependent implementations for the Shared Clipboard host service ("backends"), + * called *only* by the host service. + * @{ + */ +/** + * Structure for keeping Shared Clipboard backend instance data. + */ +typedef struct SHCLBACKEND +{ + /** Callback table to use. + * Some callbacks might be optional and therefore NULL -- see the table for more details. */ + SHCLCALLBACKS Callbacks; +} SHCLBACKEND; +/** Pointer to a Shared Clipboard backend. */ +typedef SHCLBACKEND *PSHCLBACKEND; + +/** + * Called on initialization. + * + * @param pBackend Shared Clipboard backend to initialize. + * @param pTable The HGCM service call and parameter table. Mainly for + * adjusting the limits. + */ +int ShClBackendInit(PSHCLBACKEND pBackend, VBOXHGCMSVCFNTABLE *pTable); + +/** + * Called on destruction. + * + * @param pBackend Shared Clipboard backend to destroy. + */ +void ShClBackendDestroy(PSHCLBACKEND pBackend); + +/** + * Called when a new HGCM client connects. + * + * @param pBackend Shared Clipboard backend to set callbacks for. + * @param pCallbacks Backend callbacks to use. + * When NULL is specified, the backend's default callbacks are being used. + */ +void ShClBackendSetCallbacks(PSHCLBACKEND pBackend, PSHCLCALLBACKS pCallbacks); + +/** + * Called when a new HGCM client connects. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to connect to. + * @param pClient Shared Clipboard client context. + * @param fHeadless Whether this is a headless connection or not. + */ +int ShClBackendConnect(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, bool fHeadless); + +/** + * Called when a HGCM client disconnects. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to disconnect from. + * @param pClient Shared Clipboard client context. + */ +int ShClBackendDisconnect(PSHCLBACKEND pBackend, PSHCLCLIENT pClient); + +/** + * Called when the guest reports available clipboard formats to the host OS. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to announce formats to. + * @param pClient Shared Clipboard client context. + * @param fFormats The announced formats from the guest, + * VBOX_SHCL_FMT_XXX. + */ +int ShClBackendReportFormats(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, SHCLFORMATS fFormats); + +/** + * Called when the guest wants to read host clipboard data. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to read data from. + * @param pClient Shared Clipboard client context. + * @param pCmdCtx Shared Clipboard command context. + * @param uFormat Clipboard format to read. + * @param pvData Where to return the read clipboard data. + * @param cbData Size (in bytes) of buffer where to return the clipboard data. + * @param pcbActual Where to return the amount of bytes read. + * + * @todo Document: Can return VINF_HGCM_ASYNC_EXECUTE to defer returning read + * data + */ +int ShClBackendReadData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, + void *pvData, uint32_t cbData, uint32_t *pcbActual); + +/** + * Called when the guest writes clipboard data to the host. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to write data to. + * @param pClient Shared Clipboard client context. + * @param pCmdCtx Shared Clipboard command context. + * @param uFormat Clipboard format to write. + * @param pvData Clipboard data to write. + * @param cbData Size (in bytes) of buffer clipboard data to write. + */ +int ShClBackendWriteData(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLCLIENTCMDCTX pCmdCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData); + +/** + * Called when synchronization of the clipboard contents of the host clipboard with the guest is needed. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to synchronize. + * @param pClient Shared Clipboard client context. + */ +int ShClBackendSync(PSHCLBACKEND pBackend, PSHCLCLIENT pClient); +/** @} */ + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** @name Host implementations for Shared Clipboard transfers. + * @{ + */ +/** + * Called after a transfer got created. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to use. + * @param pClient Shared Clipboard client context. + * @param pTransfer Shared Clipboard transfer created. + */ +int ShClBackendTransferCreate(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer); +/** + * Called before a transfer gets destroyed. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to use. + * @param pClient Shared Clipboard client context. + * @param pTransfer Shared Clipboard transfer to destroy. + */ +int ShClBackendTransferDestroy(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer); +/** + * Called when getting (determining) the transfer roots on the host side. + * + * @returns VBox status code. + * @param pBackend Shared Clipboard backend to use. + * @param pClient Shared Clipboard client context. + * @param pTransfer Shared Clipboard transfer to get roots for. + */ +int ShClBackendTransferGetRoots(PSHCLBACKEND pBackend, PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer); +/** @} */ +#endif + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** @name Internal Shared Clipboard transfer host service functions. + * @{ + */ +int shClSvcTransferHandler(PSHCLCLIENT pClient, VBOXHGCMCALLHANDLE callHandle, uint32_t u32Function, + uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival); +int shClSvcTransferHostHandler(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); +/** @} */ + +/** @name Shared Clipboard transfer interface implementations for the host service. + * @{ + */ +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP + +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ + +int shClSvcTransferIfaceGetRoots(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList); + +int shClSvcTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList); +int shClSvcTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList); +int shClSvcTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr); +int shClSvcTransferIfaceListHdrWrite(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr); +int shClSvcTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry); +int shClSvcTransferIfaceListEntryWrite(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry); + +int shClSvcTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, + PSHCLOBJHANDLE phObj); +int shClSvcTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj); +int shClSvcTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, + void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead); +int shClSvcTransferIfaceObjWrite(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, + void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten); +/** @} */ + +/** @name Shared Clipboard transfer callbacks for the host service. + * @{ + */ +DECLCALLBACK(void) VBoxSvcClipboardTransferPrepareCallback(PSHCLTXPROVIDERCTX pCtx); +DECLCALLBACK(void) VBoxSvcClipboardDataHeaderCompleteCallback(PSHCLTXPROVIDERCTX pCtx); +DECLCALLBACK(void) VBoxSvcClipboardDataCompleteCallback(PSHCLTXPROVIDERCTX pCtx); +DECLCALLBACK(void) VBoxSvcClipboardTransferCompleteCallback(PSHCLTXPROVIDERCTX pCtx, int rc); +DECLCALLBACK(void) VBoxSvcClipboardTransferCanceledCallback(PSHCLTXPROVIDERCTX pCtx); +DECLCALLBACK(void) VBoxSvcClipboardTransferErrorCallback(PSHCLTXPROVIDERCTX pCtx, int rc); +/** @} */ +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +/* Host unit testing interface */ +#ifdef UNIT_TEST +uint32_t TestClipSvcGetMode(void); +#endif + +#endif /* !VBOX_INCLUDED_SRC_SharedClipboard_VBoxSharedClipboardSvc_internal_h */ + |