diff options
Diffstat (limited to 'include/VBox/GuestHost')
-rw-r--r-- | include/VBox/GuestHost/DragAndDrop.h | 350 | ||||
-rw-r--r-- | include/VBox/GuestHost/DragAndDropDefs.h | 112 | ||||
-rw-r--r-- | include/VBox/GuestHost/GuestControl.h | 236 | ||||
-rw-r--r-- | include/VBox/GuestHost/HGCMMock.h | 804 | ||||
-rw-r--r-- | include/VBox/GuestHost/HGCMMockUtils.h | 427 | ||||
-rw-r--r-- | include/VBox/GuestHost/Makefile.kup | 0 | ||||
-rw-r--r-- | include/VBox/GuestHost/SharedClipboard-transfers.h | 993 | ||||
-rw-r--r-- | include/VBox/GuestHost/SharedClipboard-win.h | 419 | ||||
-rw-r--r-- | include/VBox/GuestHost/SharedClipboard-x11.h | 187 | ||||
-rw-r--r-- | include/VBox/GuestHost/SharedClipboard.h | 354 | ||||
-rw-r--r-- | include/VBox/GuestHost/clipboard-helper.h | 250 |
11 files changed, 4132 insertions, 0 deletions
diff --git a/include/VBox/GuestHost/DragAndDrop.h b/include/VBox/GuestHost/DragAndDrop.h new file mode 100644 index 00000000..cacd97b5 --- /dev/null +++ b/include/VBox/GuestHost/DragAndDrop.h @@ -0,0 +1,350 @@ +/* $Id: DragAndDrop.h $ */ +/** @file + * DnD - Shared functions between host and guest. + */ + +/* + * Copyright (C) 2014-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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_DragAndDrop_h +#define VBOX_INCLUDED_GuestHost_DragAndDrop_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/assert.h> +#include <iprt/fs.h> +#include <iprt/list.h> + +#include <VBox/GuestHost/DragAndDropDefs.h> + +/** DnDURIDroppedFiles flags. */ +typedef uint32_t DNDURIDROPPEDFILEFLAGS; + +/** No flags specified. */ +#define DNDURIDROPPEDFILE_FLAGS_NONE 0 + +/** + * Structure for keeping a DnD dropped files entry. + */ +typedef struct DNDDROPPEDFILESENTRY +{ + RTLISTNODE Node; + char *pszPath; +} DNDDROPPEDFILESENTRY; +/** Pointer to a DnD dropped files entry. */ +typedef DNDDROPPEDFILESENTRY *PDNDDROPPEDFILESENTRY; + +/** + * Structure for maintaining a "dropped files" directory + * on the host or guest. This will contain all received files & directories + * for a single drag and drop operation. + * + * In case of a failed drag and drop operation this can also + * perform a gentle rollback if required. + */ +typedef struct DNDDROPPEDFILES +{ + /** Open flags. */ + uint32_t m_fOpen; + /** Directory handle for drop directory. */ + RTDIR m_hDir; + /** Absolute path to drop directory. */ + char *pszPathAbs; + /** List for holding created directories in the case of a rollback. */ + RTLISTANCHOR m_lstDirs; + /** List for holding created files in the case of a rollback. */ + RTLISTANCHOR m_lstFiles; +} DNDDROPPEDFILES; +/** Pointer to a DnD dropped files directory. */ +typedef DNDDROPPEDFILES *PDNDDROPPEDFILES; + +int DnDDroppedFilesInit(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesInitEx(PDNDDROPPEDFILES pDF, const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags); +void DnDDroppedFilesDestroy(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesAddFile(PDNDDROPPEDFILES pDF, const char *pszFile); +int DnDDroppedFilesAddDir(PDNDDROPPEDFILES pDF, const char *pszDir); +int DnDDroppedFilesClose(PDNDDROPPEDFILES pDF); +bool DnDDroppedFilesIsOpen(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesOpenEx(PDNDDROPPEDFILES pDF, const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags); +int DnDDroppedFilesOpenTemp(PDNDDROPPEDFILES pDF, DNDURIDROPPEDFILEFLAGS fFlags); +const char *DnDDroppedFilesGetDirAbs(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesReopen(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesReset(PDNDDROPPEDFILES pDF, bool fDelete); +int DnDDroppedFilesRollback(PDNDDROPPEDFILES pDF); + +const char *DnDHostMsgToStr(uint32_t uMsg); +const char *DnDGuestMsgToStr(uint32_t uMsg); +const char *DnDActionToStr(VBOXDNDACTION uAction); + char *DnDActionListToStrA(VBOXDNDACTIONLIST fActionList); +const char *DnDStateToStr(VBOXDNDSTATE enmState); + +bool DnDMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax); +bool DnDMIMENeedsDropDir(const char *pcszFormat, size_t cchFormatMax); + +int DnDPathValidate(const char *pcszPath, bool fMustExist); + +/** DnD path conversion flags. */ +typedef uint32_t DNDPATHCONVERTFLAGS; + +/** No flags specified. + * This will convert the path to the universal tansport style. */ +#define DNDPATHCONVERT_FLAGS_TRANSPORT 0 +/** Converts the path to a OS-dependent path. */ +#define DNDPATHCONVERT_FLAGS_TO_DOS RT_BIT(0) + +/** Mask of all valid DnD path conversion flags. */ +#define DNDPATHCONVERT_FLAGS_VALID_MASK UINT32_C(0x1) + +int DnDPathConvert(char *pszPath, size_t cbPath, DNDPATHCONVERTFLAGS fFlags); +int DnDPathSanitizeFileName(char *pszPath, size_t cbPath); +int DnDPathRebase(const char *pcszPathAbs, const char *pcszBaseOld, const char *pcszBaseNew, char **ppszPath); + +/** DnDTransferObject flags. */ +typedef uint32_t DNDTRANSFEROBJECTFLAGS; + +/** No flags specified. */ +#define DNDTRANSFEROBJECT_FLAGS_NONE 0 + +/** Mask of all valid DnD transfer object flags. */ +#define DNDTRANSFEROBJECT_FLAGS_VALID_MASK UINT32_C(0x0) + +/** + * Enumeration for specifying a transfer object type. + */ +typedef enum DNDTRANSFEROBJTYPE +{ + /** Unknown type, do not use. */ + DNDTRANSFEROBJTYPE_UNKNOWN = 0, + /** Object is a file. */ + DNDTRANSFEROBJTYPE_FILE, + /** Object is a directory. */ + DNDTRANSFEROBJTYPE_DIRECTORY, + /** The usual 32-bit hack. */ + DNDTRANSFEROBJTYPE_32BIT_HACK = 0x7fffffff +} DNDTRANSFEROBJTYPE; + +/** + * Enumeration for specifying a path style. + */ +typedef enum DNDTRANSFEROBJPATHSTYLE +{ + /** Transport style (UNIX-y), the default. */ + DNDTRANSFEROBJPATHSTYLE_TRANSPORT = 0, + /** DOS style, containing back slashes. */ + DNDTRANSFEROBJPATHSTYLE_DOS, + /** The usual 32-bit hack. */ + DNDTRANSFEROBJPATHSTYLE_32BIT_HACK = 0x7fffffff +} DNDTRANSFEROBJPATHSTYLE; + +/** + * Structure for keeping a DnD transfer object. + */ +typedef struct DNDTRANSFEROBJECT +{ + RTLISTNODE Node; + /** The object's type. */ + DNDTRANSFEROBJTYPE enmType; + /** Index (in characters, UTF-8) at which the first destination segment starts. */ + uint16_t idxDst; + /** Allocated path. Includdes the absolute source path (if any) + destination segments. + * Transport (IPRT) style. */ + char *pszPath; + + /** Union containing data depending on the object's type. */ + union + { + /** Structure containing members for objects that + * are files. */ + struct + { + /** File handle. */ + RTFILE hFile; + /** File system object information of this file. */ + RTFSOBJINFO objInfo; + /** Bytes to proces for reading/writing. */ + uint64_t cbToProcess; + /** Bytes processed reading/writing. */ + uint64_t cbProcessed; + } File; + struct + { + /** Directory handle. */ + RTDIR hDir; + /** File system object information of this directory. */ + RTFSOBJINFO objInfo; + } Dir; + } u; +} DNDTRANSFEROBJECT; +/** Pointer to a DnD transfer object. */ +typedef DNDTRANSFEROBJECT *PDNDTRANSFEROBJECT; + +int DnDTransferObjectInit(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectInitEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJTYPE enmType, const char *pcszPathSrcAbs, const char *pcszPathDst); +void DnDTransferObjectDestroy(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectClose(PDNDTRANSFEROBJECT pObj); +void DnDTransferObjectReset(PDNDTRANSFEROBJECT pObj); +const char *DnDTransferObjectGetSourcePath(PDNDTRANSFEROBJECT pObj); +const char *DnDTransferObjectGetDestPath(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectGetDestPathEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJPATHSTYLE enmStyle, char *pszBuf, size_t cbBuf); +RTFMODE DnDTransferObjectGetMode(PDNDTRANSFEROBJECT pObj); +uint64_t DnDTransferObjectGetProcessed(PDNDTRANSFEROBJECT pObj); +uint64_t DnDTransferObjectGetSize(PDNDTRANSFEROBJECT pObj); +DNDTRANSFEROBJTYPE DnDTransferObjectGetType(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectSetSize(PDNDTRANSFEROBJECT pObj, uint64_t cbSize); +bool DnDTransferObjectIsComplete(PDNDTRANSFEROBJECT pObj); +bool DnDTransferObjectIsOpen(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectOpen(PDNDTRANSFEROBJECT pObj, uint64_t fOpen, RTFMODE fMode, DNDTRANSFEROBJECTFLAGS fFlags); +int DnDTransferObjectQueryInfo(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectRead(PDNDTRANSFEROBJECT pObj, void *pvBuf, size_t cbBuf, uint32_t *pcbRead); +int DnDTransferObjectWrite(PDNDTRANSFEROBJECT pObj, const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten); + +/** Defines the default chunk size of DnD data transfers. + * Supported on all (older) Guest Additions which also support DnD. */ +#define DND_DEFAULT_CHUNK_SIZE _64K + +/** Separator for a formats list. */ +#define DND_FORMATS_SEPARATOR_STR "\r\n" + +/** Default URI list path separator, if not specified otherwise. + * + * This is there for hysterical raisins, to not break older Guest Additions. + ** @todo Get rid of this. */ +#define DND_PATH_SEPARATOR_STR "\r\n" + +/** DnDTransferList flags. */ +typedef uint32_t DNDTRANSFERLISTFLAGS; + +/** No flags specified. */ +#define DNDTRANSFERLIST_FLAGS_NONE 0 +/** Enables recurisve directory handling. */ +#define DNDTRANSFERLIST_FLAGS_RECURSIVE RT_BIT(0) +/** Resolve all symlinks. Currently not supported and will be ignored. */ +#define DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS RT_BIT(1) +/** Keep the files + directory entries open while + * being in this list. */ +#define DNDTRANSFERLIST_FLAGS_KEEP_OPEN RT_BIT(2) +/** Lazy loading: Only enumerate sub directories when needed. Not implemented yet. + ** @todo Implement lazy loading. */ +#define DNDTRANSFERLIST_FLAGS_LAZY RT_BIT(3) + +/** Mask of all valid DnD transfer list flags. */ +#define DNDTRANSFERLIST_FLAGS_VALID_MASK UINT32_C(0xF) + +/** + * Enumeration for specifying a transfer list format. + */ +typedef enum DNDTRANSFERLISTFMT +{ + /** Unknown format, do not use. */ + DNDTRANSFERLISTFMT_UNKNOWN = 0, + /** Native format. */ + DNDTRANSFERLISTFMT_NATIVE, + /** URI format. */ + DNDTRANSFERLISTFMT_URI, + /** The usual 32-bit hack. */ + DNDTRANSFERLISTFMT_32BIT_HACK = 0x7fffffff +} DNDTRANSFERLISTFMT; + +/** + * Structure for keeping a DnD transfer list root entry. + * + * A root entry always is relative to the parent list maintaining it. + */ +typedef struct DNDTRANSFERLISTROOT +{ + /** List node. */ + RTLISTNODE Node; + /** Pointer to the allocated root path. + * - Relative to the list's root path + * - Always ends with a trailing slash + * - Always stored in transport style (UNIX-y). */ + char *pszPathRoot; +} DNDTRANSFERLISTROOT; +/** Pointer to a DnD list root entry. */ +typedef DNDTRANSFERLISTROOT *PDNDTRANSFERLISTROOT; + +/** + * Struct for keeping a DnD transfer list. + * + * All entries must share a common (absolute) root path. For different root paths another transfer list is needed. + */ +typedef struct DNDTRANSFERLIST +{ + /** Absolute root path of this transfer list, in native path style. + * Always ends with a separator. */ + char *pszPathRootAbs; + /** List of all relative (to \a pszPathRootAbs) top-level file/directory entries, of type DNDTRANSFERLISTROOT. + * Note: All paths are stored internally in transport style (UNIX paths) for + * easier conversion/handling! */ + RTLISTANCHOR lstRoot; + /** Total number of all transfer root entries. */ + uint64_t cRoots; + /** List of all transfer objects added, of type DNDTRANSFEROBJECT. + * + * The order of objects being added is crucial for traversing the tree. + * In other words, sub directories must come first before its contents. */ + RTLISTANCHOR lstObj; + /** Total number of all transfer objects. */ + uint64_t cObj; + /** Total size of all transfer objects, that is, the file + * size of all objects (in bytes). + * Note: Do *not* size_t here, as we also want to support large files + * on 32-bit guests. */ + uint64_t cbObjTotal; +} DNDTRANSFERLIST; +/** Pointer to a DNDTRANSFERLIST struct. */ +typedef DNDTRANSFERLIST *PDNDTRANSFERLIST; + +int DnDTransferListInit(PDNDTRANSFERLIST pList); +int DnDTransferListInitEx(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs, DNDTRANSFERLISTFMT enmFmt); +void DnDTransferListDestroy(PDNDTRANSFERLIST pList); +void DnDTransferListReset(PDNDTRANSFERLIST pList); + +int DnDTransferListAppendPath(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPath, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendPathsFromBuffer(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendPathsFromArray(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendRootsFromBuffer(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendRootsFromArray(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags); + +int DnDTransferListGetRootsEx(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pcszPathBase, const char *pcszSeparator, char **ppszBuffer, size_t *pcbBuffer); +int DnDTransferListGetRoots(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, char **ppszBuffer, size_t *pcbBuffer); +uint64_t DnDTransferListGetRootCount(PDNDTRANSFERLIST pList); +const char *DnDTransferListGetRootPathAbs(PDNDTRANSFERLIST pList); + +PDNDTRANSFEROBJECT DnDTransferListObjGetFirst(PDNDTRANSFERLIST pList); +void DnDTransferListObjRemove(PDNDTRANSFERLIST pList, PDNDTRANSFEROBJECT pObj); +void DnDTransferListObjRemoveFirst(PDNDTRANSFERLIST pList); +uint64_t DnDTransferListObjCount(PDNDTRANSFERLIST pList); +uint64_t DnDTransferListObjTotalBytes(PDNDTRANSFERLIST pList); + +#endif /* !VBOX_INCLUDED_GuestHost_DragAndDrop_h */ + diff --git a/include/VBox/GuestHost/DragAndDropDefs.h b/include/VBox/GuestHost/DragAndDropDefs.h new file mode 100644 index 00000000..b33521af --- /dev/null +++ b/include/VBox/GuestHost/DragAndDropDefs.h @@ -0,0 +1,112 @@ +/** @file + * Drag and Drop definitions - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2018-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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_DragAndDropDefs_h +#define VBOX_INCLUDED_GuestHost_DragAndDropDefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/* + * The mode of operations. + */ +#define VBOX_DRAG_AND_DROP_MODE_OFF 0 +#define VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST 1 +#define VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST 2 +#define VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL 3 + +#define VBOX_DND_ACTION_IGNORE UINT32_C(0) +#define VBOX_DND_ACTION_COPY RT_BIT_32(0) +#define VBOX_DND_ACTION_MOVE RT_BIT_32(1) +#define VBOX_DND_ACTION_LINK RT_BIT_32(2) + +/** A single DnD action. */ +typedef uint32_t VBOXDNDACTION; +/** A list of (OR'ed) DnD actions. */ +typedef uint32_t VBOXDNDACTIONLIST; + +#define hasDnDCopyAction(a) ((a) & VBOX_DND_ACTION_COPY) +#define hasDnDMoveAction(a) ((a) & VBOX_DND_ACTION_MOVE) +#define hasDnDLinkAction(a) ((a) & VBOX_DND_ACTION_LINK) + +#define isDnDIgnoreAction(a) ((a) == VBOX_DND_ACTION_IGNORE) +#define isDnDCopyAction(a) ((a) == VBOX_DND_ACTION_COPY) +#define isDnDMoveAction(a) ((a) == VBOX_DND_ACTION_MOVE) +#define isDnDLinkAction(a) ((a) == VBOX_DND_ACTION_LINK) + +/** @def VBOX_DND_FORMATS_DEFAULT + * Default drag'n drop formats. + * Note: If you add new entries here, make sure you test those + * with all supported guest OSes! + */ +#define VBOX_DND_FORMATS_DEFAULT \ + "text/uri-list", \ + /* Text. */ \ + "text/html", \ + "text/plain;charset=utf-8", \ + "text/plain;charset=utf-16", \ + "text/plain", \ + "text/richtext", \ + "UTF8_STRING", \ + "TEXT", \ + "STRING", \ + /* OpenOffice formats. */ \ + /* See: https://wiki.openoffice.org/wiki/Documentation/DevGuide/OfficeDev/Common_Application_Features#OpenOffice.org_Clipboard_Data_Formats */ \ + "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"", \ + "application/x-openoffice;windows_formatname=\"Bitmap\"" + +/** + * Enumeration for keeping a DnD state. + */ +typedef enum +{ + VBOXDNDSTATE_UNKNOWN = 0, + VBOXDNDSTATE_ENTERED, + VBOXDNDSTATE_LEFT, + VBOXDNDSTATE_QUERY_FORMATS, + VBOXDNDSTATE_QUERY_STATUS, + VBOXDNDSTATE_DRAGGING, + VBOXDNDSTATE_DROP_STARTED, + VBOXDNDSTATE_DROP_ENDED, + VBOXDNDSTATE_CANCELLED, + VBOXDNDSTATE_ERROR +} VBOXDNDSTATE; +/** Pointer to a DnD state. */ +typedef VBOXDNDSTATE *PVBOXDNDSTATE; + +#endif /* !VBOX_INCLUDED_GuestHost_DragAndDropDefs_h */ + diff --git a/include/VBox/GuestHost/GuestControl.h b/include/VBox/GuestHost/GuestControl.h new file mode 100644 index 00000000..75ddbf68 --- /dev/null +++ b/include/VBox/GuestHost/GuestControl.h @@ -0,0 +1,236 @@ +/* $Id: GuestControl.h $ */ +/** @file + * Guest Control - Common Guest and Host Code. + * + * @todo r=bird: Just merge this with GuestControlSvc.h! + */ + +/* + * Copyright (C) 2016-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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_GuestControl_h +#define VBOX_INCLUDED_GuestHost_GuestControl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +/* Everything defined in this file lives in this namespace. */ +namespace guestControl { + +/** + * Process status when executed in the guest. + */ +enum eProcessStatus +{ + /** Process is in an undefined state. */ + PROC_STS_UNDEFINED = 0, + /** Process has been started. */ + PROC_STS_STARTED = 1, + /** Process terminated normally. */ + PROC_STS_TEN = 2, + /** Process terminated via signal. */ + PROC_STS_TES = 3, + /** Process terminated abnormally. */ + PROC_STS_TEA = 4, + /** Process timed out and was killed. */ + PROC_STS_TOK = 5, + /** Process timed out and was not killed successfully. */ + PROC_STS_TOA = 6, + /** Service/OS is stopping, process was killed. */ + PROC_STS_DWN = 7, + /** Something went wrong (error code in flags). */ + PROC_STS_ERROR = 8 +}; + +/** + * Input flags, set by the host. This is needed for + * handling flags on the guest side. + * Note: Has to match Main's ProcessInputFlag_* flags! + */ +#define GUEST_PROC_IN_FLAG_NONE 0x0 +#define GUEST_PROC_IN_FLAG_EOF RT_BIT(0) + +/** + * Guest session creation flags. + * Only handled internally at the moment. + */ +#define SESSIONCREATIONFLAG_NONE 0x0 + +/** @name DIRREMOVEREC_FLAG_XXX - Guest directory removement flags. + * Essentially using what IPRT's RTDIRRMREC_F_ + * defines have to offer. + * @{ + */ +/** No remove flags specified. */ +#define DIRREMOVEREC_FLAG_NONE UINT32_C(0x0) +/** Recursively deletes the directory contents. */ +#define DIRREMOVEREC_FLAG_RECURSIVE RT_BIT(0) +/** Delete the content of the directory and the directory itself. */ +#define DIRREMOVEREC_FLAG_CONTENT_AND_DIR RT_BIT(1) +/** Only delete the content of the directory, omit the directory it self. */ +#define DIRREMOVEREC_FLAG_CONTENT_ONLY RT_BIT(2) +/** Mask of valid flags. */ +#define DIRREMOVEREC_FLAG_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** @name GUEST_PROC_CREATE_FLAG_XXX - Guest process creation flags. + * @note Has to match Main's ProcessCreateFlag_* flags! + * @{ + */ +#define GUEST_PROC_CREATE_FLAG_NONE UINT32_C(0x0) +#define GUEST_PROC_CREATE_FLAG_WAIT_START RT_BIT(0) +#define GUEST_PROC_CREATE_FLAG_IGNORE_ORPHANED RT_BIT(1) +#define GUEST_PROC_CREATE_FLAG_HIDDEN RT_BIT(2) +#define GUEST_PROC_CREATE_FLAG_PROFILE RT_BIT(3) +#define GUEST_PROC_CREATE_FLAG_WAIT_STDOUT RT_BIT(4) +#define GUEST_PROC_CREATE_FLAG_WAIT_STDERR RT_BIT(5) +#define GUEST_PROC_CREATE_FLAG_EXPAND_ARGUMENTS RT_BIT(6) +#define GUEST_PROC_CREATE_FLAG_UNQUOTED_ARGS RT_BIT(7) +/** @} */ + +/** @name GUEST_PROC_OUT_H_XXX - Pipe handle IDs used internally for referencing + * to a certain pipe buffer. + * @{ + */ +#define GUEST_PROC_OUT_H_STDOUT_DEPRECATED 0 /**< Needed for VBox hosts < 4.1.0. */ +#define GUEST_PROC_OUT_H_STDOUT 1 +#define GUEST_PROC_OUT_H_STDERR 2 +/** @} */ + +/** @name PATHRENAME_FLAG_XXX - Guest path rename flags. + * Essentially using what IPRT's RTPATHRENAME_FLAGS_XXX have to offer. + * @{ + */ +/** Do not replace anything. */ +#define PATHRENAME_FLAG_NO_REPLACE UINT32_C(0) +/** This will replace attempt any target which isn't a directory. */ +#define PATHRENAME_FLAG_REPLACE RT_BIT(0) +/** Don't allow symbolic links as part of the path. */ +#define PATHRENAME_FLAG_NO_SYMLINKS RT_BIT(1) +/** Mask of valid flags. */ +#define PATHRENAME_FLAG_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** @name GUEST_SHUTDOWN_FLAG_XXX - Guest shutdown flags. + * Must match Main's GuestShutdownFlag_ definitions. + * @{ + */ +#define GUEST_SHUTDOWN_FLAG_NONE UINT32_C(0) +#define GUEST_SHUTDOWN_FLAG_POWER_OFF RT_BIT(0) +#define GUEST_SHUTDOWN_FLAG_REBOOT RT_BIT(1) +#define GUEST_SHUTDOWN_FLAG_FORCE RT_BIT(2) +/** @} */ + +/** @name Defines for default (initial) guest process buffer lengths. + * Note: These defaults were the maximum values before; so be careful when raising those in order to + * not break running with older Guest Additions. + * @{ + */ +#define GUEST_PROC_DEF_CMD_LEN _1K +#define GUEST_PROC_DEF_ARGS_LEN _1K +#define GUEST_PROC_DEF_ENV_LEN _1K +#define GUEST_PROC_DEF_USER_LEN 128 +#define GUEST_PROC_DEF_PASSWORD_LEN 128 +#define GUEST_PROC_DEF_DOMAIN_LEN 256 +/** @} */ + +/** @name Defines for maximum guest process buffer lengths. + * @{ + */ +#define GUEST_PROC_MAX_CMD_LEN _1M +#define GUEST_PROC_MAX_ARGS_LEN _2M +#define GUEST_PROC_MAX_ENV_LEN _4M +#define GUEST_PROC_MAX_USER_LEN _64K +#define GUEST_PROC_MAX_PASSWORD_LEN _64K +#define GUEST_PROC_MAX_DOMAIN_LEN _64K +/** @} */ + +/** @name Internal tools built into VBoxService which are used in order + * to accomplish tasks host<->guest. + * @{ + */ +#define VBOXSERVICE_TOOL_CAT "vbox_cat" +#define VBOXSERVICE_TOOL_LS "vbox_ls" +#define VBOXSERVICE_TOOL_RM "vbox_rm" +#define VBOXSERVICE_TOOL_MKDIR "vbox_mkdir" +#define VBOXSERVICE_TOOL_MKTEMP "vbox_mktemp" +#define VBOXSERVICE_TOOL_STAT "vbox_stat" +/** @} */ + +/** Special process exit codes for "vbox_cat". */ +typedef enum VBOXSERVICETOOLBOX_CAT_EXITCODE +{ + VBOXSERVICETOOLBOX_CAT_EXITCODE_ACCESS_DENIED = RTEXITCODE_END, + VBOXSERVICETOOLBOX_CAT_EXITCODE_FILE_NOT_FOUND, + VBOXSERVICETOOLBOX_CAT_EXITCODE_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_CAT_EXITCODE_SHARING_VIOLATION, + VBOXSERVICETOOLBOX_CAT_EXITCODE_IS_A_DIRECTORY, + /** The usual 32-bit type hack. */ + VBOXSERVICETOOLBOX_CAT_32BIT_HACK = 0x7fffffff +} VBOXSERVICETOOLBOX_CAT_EXITCODE; + +/** Special process exit codes for "vbox_stat". */ +typedef enum VBOXSERVICETOOLBOX_STAT_EXITCODE +{ + VBOXSERVICETOOLBOX_STAT_EXITCODE_ACCESS_DENIED = RTEXITCODE_END, + VBOXSERVICETOOLBOX_STAT_EXITCODE_FILE_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_NET_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_INVALID_NAME, + /** The usual 32-bit type hack. */ + VBOXSERVICETOOLBOX_STAT_32BIT_HACK = 0x7fffffff +} VBOXSERVICETOOLBOX_STAT_EXITCODE; + +/** + * Input status, reported by the client. + */ +enum eInputStatus +{ + /** Input is in an undefined state. */ + INPUT_STS_UNDEFINED = 0, + /** Input was written (partially, see cbProcessed). */ + INPUT_STS_WRITTEN = 1, + /** Input failed with an error (see flags for rc). */ + INPUT_STS_ERROR = 20, + /** Process has abandoned / terminated input handling. */ + INPUT_STS_TERMINATED = 21, + /** Too much input data. */ + INPUT_STS_OVERFLOW = 30 +}; + + + +} /* namespace guestControl */ + +#endif /* !VBOX_INCLUDED_GuestHost_GuestControl_h */ + diff --git a/include/VBox/GuestHost/HGCMMock.h b/include/VBox/GuestHost/HGCMMock.h new file mode 100644 index 00000000..ba85349a --- /dev/null +++ b/include/VBox/GuestHost/HGCMMock.h @@ -0,0 +1,804 @@ +/* $Id: HGCMMock.h $ */ +/** @file + * HGCMMock.h: Mocking framework for testing HGCM-based host services + + * Vbgl code on the host side. + * + * Goal is to run host service + Vbgl code as unmodified as + * possible as part of testcases to gain test coverage which + * otherwise wouldn't possible for heavily user-centric features + * like Shared Clipboard or drag'n drop (DnD). + */ + +/* + * Copyright (C) 2022-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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_HGCMMock_h +#define VBOX_INCLUDED_GuestHost_HGCMMock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/types.h> + +#include <iprt/asm.h> +#include <iprt/assert.h> +#include <iprt/list.h> +#include <iprt/mem.h> +#include <iprt/rand.h> +#include <iprt/semaphore.h> +#include <iprt/test.h> +#include <iprt/time.h> +#include <iprt/thread.h> +#include <iprt/utf16.h> + +#include <VBox/err.h> +#include <VBox/VBoxGuestLib.h> +#include <VBox/hgcmsvc.h> + + +/********************************************************************************************************************************* +* Definitions. * +*********************************************************************************************************************************/ + +#if defined(IN_RING3) /* Only R3 parts implemented so far. */ + +RT_C_DECLS_BEGIN + +DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable); + +RT_C_DECLS_END + +# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL + +/** Simple call handle structure for the guest call completion callback. */ +typedef struct VBOXHGCMCALLHANDLE_TYPEDEF +{ + /** Where to store the result code on call completion. */ + int32_t rc; +} VBOXHGCMCALLHANDLE_TYPEDEF; + +/** + * Enumeration for a HGCM mock function type. + */ +typedef enum TSTHGCMMOCKFNTYPE +{ + TSTHGCMMOCKFNTYPE_NONE = 0, + TSTHGCMMOCKFNTYPE_CONNECT, + TSTHGCMMOCKFNTYPE_DISCONNECT, + TSTHGCMMOCKFNTYPE_CALL, + TSTHGCMMOCKFNTYPE_HOST_CALL +} TSTHGCMMOCKFNTYPE; + +/** Pointer to a mock HGCM service. */ +typedef struct TSTHGCMMOCKSVC *PTSTHGCMMOCKSVC; + +/** + * Structure for mocking a server-side HGCM client. + */ +typedef struct TSTHGCMMOCKCLIENT +{ + /** Pointer to to mock service instance this client belongs to. */ + PTSTHGCMMOCKSVC pSvc; + /** Assigned HGCM client ID. */ + uint32_t idClient; + /** Opaque pointer to service-specific client data. + * Can be NULL if not being used. */ + void *pvClient; + /** Size (in bytes) of \a pvClient. */ + size_t cbClient; + /** The client's current HGCM call handle. */ + VBOXHGCMCALLHANDLE_TYPEDEF hCall; + /** Whether the current client call has an asynchronous + * call pending or not. */ + bool fAsyncExec; + /** Event semaphore to signal call completion. */ + RTSEMEVENT hEvent; +} TSTHGCMMOCKCLIENT; +/** Pointer to a mock HGCM client. */ +typedef TSTHGCMMOCKCLIENT *PTSTHGCMMOCKCLIENT; + +/** + * Structure for keeping HGCM mock function parameters. + */ +typedef struct TSTHGCMMOCKFN +{ + /** List node for storing this struct into a queue. */ + RTLISTNODE Node; + /** Function type. */ + TSTHGCMMOCKFNTYPE enmType; + /** Pointer to associated client. */ + PTSTHGCMMOCKCLIENT pClient; + /** Union keeping function-specific parameters, + * depending on \a enmType. */ + union + { + struct + { + int32_t iFunc; + uint32_t cParms; + PVBOXHGCMSVCPARM pParms; + VBOXHGCMCALLHANDLE hCall; + } Call; + struct + { + int32_t iFunc; + uint32_t cParms; + PVBOXHGCMSVCPARM pParms; + } HostCall; + } u; +} TSTHGCMMOCKFN; +/** Pointer to a HGCM mock function parameters structure. */ +typedef TSTHGCMMOCKFN *PTSTHGCMMOCKFN; + +/** + * Structure for keeping a HGCM mock service instance. + */ +typedef struct TSTHGCMMOCKSVC +{ + /** HGCM helper table to use. */ + VBOXHGCMSVCHELPERS fnHelpers; + /** HGCM service function table to use. */ + VBOXHGCMSVCFNTABLE fnTable; + /** Next HGCM client ID to assign. + * 0 is considered as being invalid. */ + HGCMCLIENTID uNextClientId; + /** Size (in bytes) of opaque pvClient area to reserve + * for a connected client. */ + size_t cbClient; + /** Array of connected HGCM mock clients. + * Currently limited to 4 clients maximum. */ + TSTHGCMMOCKCLIENT aHgcmClient[4]; + /** Thread handle for the service's main loop. */ + RTTHREAD hThread; + /** Event semaphore for signalling a message + * queue change. */ + RTSEMEVENT hEventQueue; + /** Event semaphore for clients connecting to the server. */ + RTSEMEVENT hEventConnect; + /** Number of current host calls being served. + * Currently limited to one call at a time. */ + uint8_t cHostCallers; + /** Result code of last returned host call. */ + int rcHostCall; + /** Event semaphore for host calls. */ + RTSEMEVENT hEventHostCall; + /** List (queue) of function calls to process. */ + RTLISTANCHOR lstCall; + /** Shutdown indicator flag. */ + volatile bool fShutdown; +} TSTHGCMMOCKSVC; + +/** Static HGCM service to mock. */ +static TSTHGCMMOCKSVC s_tstHgcmSvc; + +/********************************************************************************************************************************* +* Prototypes. * +*********************************************************************************************************************************/ +PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void); +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout); +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient); +int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc); + +int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); + +VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient); +VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo); + + + +/********************************************************************************************************************************* +* Internal functions * +*********************************************************************************************************************************/ + +/** + * Initializes a HGCM mock client. + * + * @return VBox status code. + * @param pClient Client instance to initialize. + * @param idClient HGCM client ID to assign. + * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate. + */ +static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient) +{ + RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT)); + + pClient->idClient = idClient; + if (cbClient) + { + pClient->pvClient = RTMemAllocZ(cbClient); + AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY); + pClient->cbClient = cbClient; + } + + return RTSemEventCreate(&pClient->hEvent); +} + +/** + * Destroys a HGCM mock client. + * + * @return VBox status code. + * @param pClient Client instance to destroy. + */ +static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient) +{ + int rc = RTSemEventDestroy(pClient->hEvent); + if (RT_SUCCESS(rc)) + { + if (pClient->pvClient) + { + Assert(pClient->cbClient); + RTMemFree(pClient->pvClient); + pClient->pvClient = NULL; + pClient->cbClient = 0; + } + + pClient->hEvent = NIL_RTSEMEVENT; + } + + return rc; +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */ +static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient) +{ + RT_NOREF(pvService); + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId]; + + int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->cbClient); + if (RT_FAILURE(rc)) + return rc; + + pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT; + pFn->pClient = pClient; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC); + AssertRCReturn(rc2, rc2); + + ASMAtomicIncU32(&pSvc->uNextClientId); + + rc2 = RTSemEventSignal(pSvc->hEventConnect); + AssertRCReturn(rc2, rc2); + + *pidClient = pClient->idClient; + + return VINF_SUCCESS; +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */ +static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient) +{ + RT_NOREF(pvService); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient]; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT; + pFn->pClient = pClient; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + + rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC); + AssertRCReturn(rc2, rc2); + + return tstHgcmMockClientDestroy(pClient); +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */ +static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, + int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) +{ + RT_NOREF(pvService, pvClient); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient]; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM); + + pFn->enmType = TSTHGCMMOCKFNTYPE_CALL; + pFn->pClient = pClient; + + pFn->u.Call.hCall = callHandle; + pFn->u.Call.iFunc = function; + pFn->u.Call.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms); + AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY); + pFn->u.Call.cParms = cParms; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + + rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT); + AssertRCReturn(rc2, rc2); + + memcpy(paParms, pFn->u.Call.pParms, cbParms); + + return VINF_SUCCESS; /** @todo Return host call rc */ +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */ +/** Note: Public for also being able to test host calls via testcases. */ +int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) +{ + RT_NOREF(pvService); + AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */ + + pSvc->cHostCallers++; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_INVALID_POINTER); + + pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL; + pFn->u.HostCall.iFunc = function; + if (cParms) + { + pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM)); + AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY); + pFn->u.HostCall.cParms = cParms; + } + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRC(rc2); + + rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT); + AssertRCReturn(rc2, rc2); + + Assert(pSvc->cHostCallers); + pSvc->cHostCallers--; + + return pSvc->rcHostCall; +} + +/** + * Call completion callback for guest calls. + * + * @return VBox status code. + * @param callHandle Call handle to complete. + * @param rc Return code to return to the caller. + */ +static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc) +{ + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + size_t i = 0; + for (; RT_ELEMENTS(pSvc->aHgcmClient); i++) + { + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i]; + if (&pClient->hCall == callHandle) /* Slow, but works for now. */ + { + if (rc == VINF_HGCM_ASYNC_EXECUTE) + { + Assert(pClient->fAsyncExec == false); + } + else /* Complete call + notify client. */ + { + callHandle->rc = rc; + + int rc2 = RTSemEventSignal(pClient->hEvent); + AssertRCReturn(rc2, rc2); + } + + return VINF_SUCCESS; + } + } + + return VERR_NOT_FOUND; +} + +/** + * Main thread of HGCM mock service. + * + * @return VBox status code. + * @param hThread Thread handle. + * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC. + */ +static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser; + + pSvc->uNextClientId = 0; + + pSvc->fnTable.cbSize = sizeof(pSvc->fnTable); + pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION; + + RT_ZERO(pSvc->fnHelpers); + pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete; + pSvc->fnTable.pHelpers = &pSvc->fnHelpers; + + int rc = VBoxHGCMSvcLoad(&pSvc->fnTable); + if (RT_SUCCESS(rc)) + { + RTThreadUserSignal(hThread); + + for (;;) + { + rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */); + if (ASMAtomicReadBool(&pSvc->fShutdown)) + { + rc = VINF_SUCCESS; + break; + } + if (rc == VERR_TIMEOUT) + continue; + + PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node); + if (pFn) + { + switch (pFn->enmType) + { + case TSTHGCMMOCKFNTYPE_CONNECT: + { + rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService, + pFn->pClient->idClient, pFn->pClient->pvClient, + VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */); + + int rc2 = RTSemEventSignal(pFn->pClient->hEvent); + AssertRC(rc2); + break; + } + + case TSTHGCMMOCKFNTYPE_DISCONNECT: + { + rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService, + pFn->pClient->idClient, pFn->pClient->pvClient); + + int rc2 = RTSemEventSignal(pFn->pClient->hEvent); + AssertRC(rc2); + break; + } + + case TSTHGCMMOCKFNTYPE_CALL: + { + pSvc->fnTable.pfnCall(NULL, pFn->u.Call.hCall, pFn->pClient->idClient, pFn->pClient->pvClient, + pFn->u.Call.iFunc, pFn->u.Call.cParms, pFn->u.Call.pParms, RTTimeMilliTS()); + + /* Note: Call will be completed in the call completion callback. */ + break; + } + + case TSTHGCMMOCKFNTYPE_HOST_CALL: + { + pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(NULL, pFn->u.HostCall.iFunc, pFn->u.HostCall.cParms, pFn->u.HostCall.pParms); + + int rc2 = RTSemEventSignal(pSvc->hEventHostCall); + AssertRC(rc2); + break; + } + + default: + AssertFailed(); + break; + } + RTListNodeRemove(&pFn->Node); + RTMemFree(pFn); + } + } + } + + return rc; +} + + +/********************************************************************************************************************************* +* Public functions * +*********************************************************************************************************************************/ + +/** + * Returns the pointer to the HGCM mock service instance. + * + * @return Pointer to HGCM mock service instance. + */ +PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void) +{ + return &s_tstHgcmSvc; +} + +/** + * Waits for a HGCM mock client to connect, extended version. + * + * @return Pointer to connected client, or NULL if ran into timeout. + * @param pSvc HGCM mock service instance. + * @param msTimeout Timeout (in ms) to wait for connection. + */ +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout) +{ + int rc = RTSemEventWait(pSvc->hEventConnect, msTimeout); + if (RT_SUCCESS(rc)) + { + Assert(pSvc->uNextClientId); + return &pSvc->aHgcmClient[pSvc->uNextClientId - 1]; + } + return NULL; +} + +/** + * Waits for a HGCM mock client to connect. + * + * @return Pointer to connected client, or NULL if waiting for connection was aborted. + * @param pSvc HGCM mock service instance. + */ +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc) +{ + return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC); +} + +/** + * Creates a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to create. + * @param cbClient Size (in bytes) of service-specific client data to + * allocate for a HGCM mock client. + */ +int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient) +{ + AssertReturn(cbClient, VERR_INVALID_PARAMETER); + + RT_ZERO(pSvc->aHgcmClient); + pSvc->fShutdown = false; + int rc = RTSemEventCreate(&pSvc->hEventQueue); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pSvc->hEventHostCall); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pSvc->hEventConnect); + if (RT_SUCCESS(rc)) + { + RTListInit(&pSvc->lstCall); + + pSvc->cbClient = cbClient; + } + } + } + + return rc; +} + +/** + * Destroys a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to destroy. + */ +int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc) +{ + int rc = RTSemEventDestroy(pSvc->hEventQueue); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventDestroy(pSvc->hEventHostCall); + if (RT_SUCCESS(rc)) + RTSemEventDestroy(pSvc->hEventConnect); + } + return rc; +} + +/** + * Starts a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to start. + */ +int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc) +{ + int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "MockSvc"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to stop. + */ +int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc) +{ + ASMAtomicWriteBool(&pSvc->fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + { + pSvc->hThread = NIL_RTTHREAD; + } + + return rc; +} + + +/********************************************************************************************************************************* +* VbglR3 stubs * +*********************************************************************************************************************************/ + +/** + * Connects to an HGCM mock service. + * + * @returns VBox status code + * @param pszServiceName Name of the host service. + * @param pidClient Where to put the client ID on success. The client ID + * must be passed to all the other calls to the service. + */ +VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient) +{ + RT_NOREF(pszServiceName); + + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient); +} + +/** + * Disconnect from an HGCM mock service. + * + * @returns VBox status code. + * @param idClient The client id returned by VbglR3HGCMConnect(). + */ +VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient) +{ + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient); +} + +/** + * Makes a fully prepared HGCM call to an HGCM mock service. + * + * @returns VBox status code. + * @param pInfo Fully prepared HGCM call info. + * @param cbInfo Size of the info. This may sometimes be larger than + * what the parameter count indicates because of + * parameter changes between versions and such. + */ +VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo) +{ + RT_NOREF(cbInfo); + + AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo)); + AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo)); + Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo); + + HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo); + PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM)); + + uint16_t i = 0; + for (; i < pInfo->cParms; i++) + { + switch (offSrcParms->type) + { + case VMMDevHGCMParmType_32bit: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT; + paDstParms[i].u.uint32 = offSrcParms->u.value32; + break; + } + + case VMMDevHGCMParmType_64bit: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT; + paDstParms[i].u.uint64 = offSrcParms->u.value64; + break; + } + + case VMMDevHGCMParmType_LinAddr: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR; + paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr; + paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb; + break; + } + + default: + AssertFailed(); + break; + } + + offSrcParms++; + } + + PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst(); + + int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall, + pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient, + pInfo->u32Function, pInfo->cParms, paDstParms); + if (RT_SUCCESS(rc2)) + { + offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo); + + for (i = 0; i < pInfo->cParms; i++) + { + paDstParms[i].type = offSrcParms->type; + switch (paDstParms[i].type) + { + case VMMDevHGCMParmType_32bit: + offSrcParms->u.value32 = paDstParms[i].u.uint32; + break; + + case VMMDevHGCMParmType_64bit: + offSrcParms->u.value64 = paDstParms[i].u.uint64; + break; + + case VMMDevHGCMParmType_LinAddr: + { + offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size; + break; + } + + default: + AssertFailed(); + break; + } + + offSrcParms++; + } + } + + RTMemFree(paDstParms); + + if (RT_SUCCESS(rc2)) + rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc; + + return rc2; +} + +#endif /* IN_RING3 */ + +#endif /* !VBOX_INCLUDED_GuestHost_HGCMMock_h */ diff --git a/include/VBox/GuestHost/HGCMMockUtils.h b/include/VBox/GuestHost/HGCMMockUtils.h new file mode 100644 index 00000000..92f5893b --- /dev/null +++ b/include/VBox/GuestHost/HGCMMockUtils.h @@ -0,0 +1,427 @@ +/* $Id */ +/** @file + * HGCMMockUtils.h: Utility functions for the HGCM Mocking framework. + * + * The utility functions are optional to the actual HGCM Mocking framework and + * can support testcases which require a more advanced setup. + * + * With this one can setup host and guest side threads, which in turn can simulate + * specific host (i.e. HGCM service) + guest (i.e. like in the Guest Addditions + * via VbglR3) scenarios. + * + * Glossary: + * + * Host thread: + * - The host thread is used as part of the actual HGCM service being tested and + * provides callbacks (@see TSTHGCMUTILSHOSTCALLBACKS) for the unit test. + * Guest thread: + * - The guest thread is used as part of the guest side and mimics + * VBoxClient / VBoxTray / VBoxService parts. (i.e. for VbglR3 calls). + * Task: + * - A task is the simplest unit of test execution and used between the guest + * and host mocking threads. + * + ** @todo Add TstHGCMSimpleHost / TstHGCMSimpleGuest wrappers along those lines: + * Callback.pfnOnClientConnected = tstOnHostClientConnected() + * TstHGCMSimpleHostInitAndStart(&Callback) + * Callback.pfnOnConnected = tstOnGuestConnected() + * TstHGCMSimpleClientInitAndStart(&Callback) + */ + +/* + * Copyright (C) 2022-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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_HGCMMockUtils_h +#define VBOX_INCLUDED_GuestHost_HGCMMockUtils_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/err.h> +#include <iprt/semaphore.h> +#include <iprt/thread.h> +#include <iprt/types.h> + + +#include <VBox/GuestHost/HGCMMock.h> +#include <VBox/VBoxGuestLib.h> + + +#if defined(IN_RING3) /* Only R3 parts implemented so far. */ + +/** Pointer to a HGCM Mock utils context. */ +typedef struct TSTHGCMUTILSCTX *PTSTHGCMUTILSCTX; + +/** + * Structure for keeping a HGCM Mock utils host service callback table. + */ +typedef struct TSTHGCMUTILSHOSTCALLBACKS +{ + DECLCALLBACKMEMBER(int, pfnOnClientConnected,(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKCLIENT pClient, void *pvUser)); +} TSTHGCMUTILSHOSTCALLBACKS; +/** Pointer to a HGCM Mock utils host callbacks table. */ +typedef TSTHGCMUTILSHOSTCALLBACKS *PTSTHGCMUTILSHOSTCALLBACKS; + +/** + * Structure for keeping a generic HGCM Mock utils task. + * + * A task is a single test unit / entity. + */ +typedef struct TSTHGCMUTILSTASK +{ + /** Completion event. */ + RTSEMEVENT hEvent; + /** Completion rc. + * Set to VERR_IPE_UNINITIALIZED_STATUS if not completed yet. */ + int rcCompleted; + /** Expected completion rc. */ + int rcExpected; + /** Pointer to opaque (testcase-specific) task parameters. + * Might be NULL if not needed / used. */ + void *pvUser; +} TSTHGCMUTILSTASK; +/** Pointer to a HGCM Mock utils task. */ +typedef TSTHGCMUTILSTASK *PTSTHGCMUTILSTASK; + +/** Callback function for HGCM Mock utils threads. */ +typedef DECLCALLBACKTYPE(int, FNTSTHGCMUTILSTHREAD,(PTSTHGCMUTILSCTX pCtx, void *pvUser)); +/** Pointer to a HGCM Mock utils guest thread callback. */ +typedef FNTSTHGCMUTILSTHREAD *PFNTSTHGCMUTILSTHREAD; + +/** + * Structure for keeping a HGCM Mock utils context. + */ +typedef struct TSTHGCMUTILSCTX +{ + /** Pointer to the HGCM Mock service instance to use. */ + PTSTHGCMMOCKSVC pSvc; + /** Currently we only support one task at a time. */ + TSTHGCMUTILSTASK Task; + struct + { + RTTHREAD hThread; + volatile bool fShutdown; + PFNTSTHGCMUTILSTHREAD pfnThread; + void *pvUser; + } Guest; + struct + { + RTTHREAD hThread; + volatile bool fShutdown; + TSTHGCMUTILSHOSTCALLBACKS Callbacks; + void *pvUser; + } Host; +} TSTHGCMUTILSCTX; + + +/********************************************************************************************************************************* +* Prototypes. * +*********************************************************************************************************************************/ +/** @name Context handling. + * @{ */ +void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc); +/** @} */ + +/** @name Task handling. + * @{ */ +PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx); +int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask); +void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask); +int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout); +bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask); +bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask); +void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc); +/** @} */ + +/** @name Threading. + * @{ */ +int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser); +int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx); +int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser); +int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx); +/** @} */ + + +/********************************************************************************************************************************* + * Context * + ********************************************************************************************************************************/ +/** + * Initializes a HGCM Mock utils context. + * + * @param pCtx Context to intiialize. + * @param pSvc HGCM Mock service instance to use. + */ +void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc) +{ + RT_BZERO(pCtx, sizeof(TSTHGCMUTILSCTX)); + + pCtx->pSvc = pSvc; +} + + +/********************************************************************************************************************************* + * Tasks * + ********************************************************************************************************************************/ +/** + * Returns the current task of a HGCM Mock utils context. + * + * @returns Current task of a HGCM Mock utils context. NULL if no current task found. + * @param pCtx HGCM Mock utils context. + */ +PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx) +{ + /* Currently we only support one task at a time. */ + return &pCtx->Task; +} + +/** + * Initializes a HGCM Mock utils task. + * + * @returns VBox status code. + * @param pTask Task to initialize. + */ +int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask) +{ + pTask->pvUser = NULL; + pTask->rcCompleted = pTask->rcExpected = VERR_IPE_UNINITIALIZED_STATUS; + return RTSemEventCreate(&pTask->hEvent); +} + +/** + * Destroys a HGCM Mock utils task. + * + * @param pTask Task to destroy. + */ +void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask) +{ + RTSemEventDestroy(pTask->hEvent); +} + +/** + * Waits for a HGCM Mock utils task to complete. + * + * @returns VBox status code. + * @param pTask Task to wait for. + * @param msTimeout Timeout (in ms) to wait. + */ +int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout) +{ + return RTSemEventWait(pTask->hEvent, msTimeout); +} + +/** + * Returns if the HGCM Mock utils task has been completed successfully. + * + * @returns \c true if successful, \c false if not. + * @param pTask Task to check. + */ +bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask) +{ + return pTask->rcCompleted == pTask->rcExpected; +} + +/** + * Returns if the HGCM Mock utils task has been completed (failed or succeeded). + * + * @returns \c true if completed, \c false if (still) running. + * @param pTask Task to check. + */ +bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask) +{ + return pTask->rcCompleted != VERR_IPE_UNINITIALIZED_STATUS; +} + +/** + * Signals a HGCM Mock utils task to complete its operation. + * + * @param pTask Task to complete. + * @param rc Task result to set for completion. + */ +void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc) +{ + AssertMsg(pTask->rcCompleted == VERR_IPE_UNINITIALIZED_STATUS, ("Task already completed\n")); + pTask->rcCompleted = rc; + int rc2 = RTSemEventSignal(pTask->hEvent); + AssertRC(rc2); +} + + +/********************************************************************************************************************************* + * Threading * + ********************************************************************************************************************************/ + +/** + * Thread worker for the guest side thread. + * + * @returns VBox status code. + * @param hThread Thread handle. + * @param pvUser Pointer of type PTSTHGCMUTILSCTX. + * + * @note Runs in the guest thread. + */ +static DECLCALLBACK(int) tstHGCMUtilsGuestThread(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser; + AssertPtr(pCtx); + + RTThreadUserSignal(hThread); + + if (pCtx->Guest.pfnThread) + return pCtx->Guest.pfnThread(pCtx, pCtx->Guest.pvUser); + + return VINF_SUCCESS; +} + +/** + * Starts the guest side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to start guest thread for. + * @param pFnThread Pointer to custom thread worker function to call within the guest side thread. + * @param pvUser User-supplied pointer to guest thread context data. Optional and can be NULL. + */ +int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser) +{ + pCtx->Guest.pfnThread = pFnThread; + pCtx->Guest.pvUser = pvUser; + + int rc = RTThreadCreate(&pCtx->Guest.hThread, tstHGCMUtilsGuestThread, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "tstShClGst"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pCtx->Guest.hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops the guest side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to stop guest thread for. + */ +int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx) +{ + ASMAtomicWriteBool(&pCtx->Guest.fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pCtx->Guest.hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + pCtx->Guest.hThread = NIL_RTTHREAD; + + return rc; +} + +/** + * Thread worker function for the host side HGCM service. + * + * @returns VBox status code. + * @param hThread Thread handle. + * @param pvUser Pointer of type PTSTHGCMUTILSCTX. + * + * @note Runs in the host service thread. + */ +static DECLCALLBACK(int) tstHGCMUtilsHostThreadWorker(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser; + AssertPtr(pCtx); + + int rc = VINF_SUCCESS; + + RTThreadUserSignal(hThread); + + PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst(); + + for (;;) + { + if (ASMAtomicReadBool(&pCtx->Host.fShutdown)) + break; + + /* Wait for a new (mock) HGCM client to connect. */ + PTSTHGCMMOCKCLIENT pMockClient = TstHgcmMockSvcWaitForConnectEx(pSvc, 100 /* ms */); + if (pMockClient) /* Might be NULL when timed out. */ + { + if (pCtx->Host.Callbacks.pfnOnClientConnected) + /* ignore rc */ pCtx->Host.Callbacks.pfnOnClientConnected(pCtx, pMockClient, pCtx->Host.pvUser); + } + } + + return rc; +} + +/** + * Starts the host side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to start host thread for. + * @param pCallbacks Pointer to host callback table to use. + * @param pvUser User-supplied pointer to reach into the host thread callbacks. + */ +int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser) +{ + memcpy(&pCtx->Host.Callbacks, pCallbacks, sizeof(TSTHGCMUTILSHOSTCALLBACKS)); + pCtx->Host.pvUser = pvUser; + + int rc = RTThreadCreate(&pCtx->Host.hThread, tstHGCMUtilsHostThreadWorker, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "tstShClHst"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pCtx->Host.hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops the host side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to stop host thread for. + */ +int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx) +{ + ASMAtomicWriteBool(&pCtx->Host.fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pCtx->Host.hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + pCtx->Host.hThread = NIL_RTTHREAD; + + return rc; +} + +#endif /* IN_RING3 */ + +#endif /* !VBOX_INCLUDED_GuestHost_HGCMMockUtils_h */ + diff --git a/include/VBox/GuestHost/Makefile.kup b/include/VBox/GuestHost/Makefile.kup new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/include/VBox/GuestHost/Makefile.kup diff --git a/include/VBox/GuestHost/SharedClipboard-transfers.h b/include/VBox/GuestHost/SharedClipboard-transfers.h new file mode 100644 index 00000000..2cf6fadd --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-transfers.h @@ -0,0 +1,993 @@ +/* $Id: SharedClipboard-transfers.h $ */ +/** @file + * Shared Clipboard - Shared transfer functions between host and guest. + */ + +/* + * Copyright (C) 2019-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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <map> + +#include <iprt/assert.h> +#include <iprt/critsect.h> +#include <iprt/fs.h> +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +# include <iprt/http-server.h> +#endif +#include <iprt/list.h> + +#include <iprt/cpp/list.h> +#include <iprt/cpp/ministring.h> + +#include <VBox/GuestHost/SharedClipboard.h> +#include <VBox/HostServices/VBoxClipboardSvc.h> + + +struct SHCLTRANSFER; +/** Pointer to a single shared clipboard transfer */ +typedef struct SHCLTRANSFER *PSHCLTRANSFER; + + +/** @name Shared Clipboard transfer definitions. + * @{ + */ + +/** Defines the maximum length (in chars) a Shared Clipboard transfer path can have. */ +#define SHCL_TRANSFER_PATH_MAX RTPATH_MAX + +/** + * Defines the transfer status codes. + */ +typedef enum +{ + /** No status set. */ + SHCLTRANSFERSTATUS_NONE = 0, + /** The transfer has been initialized but is not running yet. */ + SHCLTRANSFERSTATUS_INITIALIZED, + /** The transfer is active and running. */ + SHCLTRANSFERSTATUS_STARTED, + /** The transfer has been stopped. */ + SHCLTRANSFERSTATUS_STOPPED, + /** The transfer has been canceled. */ + SHCLTRANSFERSTATUS_CANCELED, + /** The transfer has been killed. */ + SHCLTRANSFERSTATUS_KILLED, + /** The transfer ran into an unrecoverable error. */ + SHCLTRANSFERSTATUS_ERROR, + /** The usual 32-bit hack. */ + SHCLTRANSFERSTATUS_32BIT_SIZE_HACK = 0x7fffffff +} SHCLTRANSFERSTATUSENUM; + +/** Defines a transfer status. */ +typedef uint32_t SHCLTRANSFERSTATUS; + +/** @} */ + +/** @name Shared Clipboard handles. + * @{ + */ + +/** A Shared Clipboard list handle. */ +typedef uint64_t SHCLLISTHANDLE; +/** Pointer to a Shared Clipboard list handle. */ +typedef SHCLLISTHANDLE *PSHCLLISTHANDLE; +/** Specifies an invalid Shared Clipboard list handle. + * @todo r=bird: The convention is NIL_SHCLLISTHANDLE. */ +#define SHCLLISTHANDLE_INVALID ((SHCLLISTHANDLE)UINT64_MAX) + +/** A Shared Clipboard object handle. */ +typedef uint64_t SHCLOBJHANDLE; +/** Pointer to a Shared Clipboard object handle. */ +typedef SHCLOBJHANDLE *PSHCLOBJHANDLE; +/** Specifies an invalid Shared Clipboard object handle. + * @todo r=bird: The convention is NIL_SHCLOBJHANDLE. */ +#define SHCLOBJHANDLE_INVALID ((SHCLOBJHANDLE)UINT64_MAX) + +/** @} */ + +/** @name Shared Clipboard open/create flags. + * @{ + */ +/** No flags. Initialization value. */ +#define SHCL_OBJ_CF_NONE UINT32_C(0x00000000) + +#if 0 /* These probably won't be needed either */ +/** Lookup only the object, do not return a handle. All other flags are ignored. */ +#define SHCL_OBJ_CF_LOOKUP UINT32_C(0x00000001) +/** Create/open a directory. */ +#define SHCL_OBJ_CF_DIRECTORY UINT32_C(0x00000004) +#endif + +/** Read/write requested access for the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_RW UINT32_C(0x00001000) +/** No access requested. */ +#define SHCL_OBJ_CF_ACCESS_NONE UINT32_C(0x00000000) +/** Read access requested. */ +#define SHCL_OBJ_CF_ACCESS_READ UINT32_C(0x00001000) + +/** Requested share access for the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_DENY UINT32_C(0x00008000) +/** Allow any access. */ +#define SHCL_OBJ_CF_ACCESS_DENYNONE UINT32_C(0x00000000) +/** Do not allow write. */ +#define SHCL_OBJ_CF_ACCESS_DENYWRITE UINT32_C(0x00008000) + +/** Requested access to attributes of the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_ATTR UINT32_C(0x00010000) +/** No access requested. */ +#define SHCL_OBJ_CF_ACCESS_ATTR_NONE UINT32_C(0x00000000) +/** Read access requested. */ +#define SHCL_OBJ_CF_ACCESS_ATTR_READ UINT32_C(0x00010000) + +/** Valid bits. */ +#define SHCL_OBJ_CF_VALID_MASK UINT32_C(0x00019000) +/** @} */ + +/** + * The available additional information in a SHCLFSOBJATTR object. + * @sa RTFSOBJATTRADD + */ +typedef enum _SHCLFSOBJATTRADD +{ + /** No additional information is available / requested. */ + SHCLFSOBJATTRADD_NOTHING = 1, + /** The additional unix attributes (SHCLFSOBJATTR::u::Unix) are + * available / requested. */ + SHCLFSOBJATTRADD_UNIX, + /** The additional extended attribute size (SHCLFSOBJATTR::u::EASize) is + * available / requested. */ + SHCLFSOBJATTRADD_EASIZE, + /** The last valid item (inclusive). + * The valid range is SHCLFSOBJATTRADD_NOTHING thru + * SHCLFSOBJATTRADD_LAST. */ + SHCLFSOBJATTRADD_LAST = SHCLFSOBJATTRADD_EASIZE, + /** The usual 32-bit hack. */ + SHCLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff +} SHCLFSOBJATTRADD; + + +/* Assert sizes of the IRPT types we're using below. */ +AssertCompileSize(RTFMODE, 4); +AssertCompileSize(RTFOFF, 8); +AssertCompileSize(RTINODE, 8); +AssertCompileSize(RTTIMESPEC, 8); +AssertCompileSize(RTDEV, 4); +AssertCompileSize(RTUID, 4); + +/** + * Shared Clipboard filesystem object attributes. + * + * @sa RTFSOBJATTR + */ +typedef struct _SHCLFSOBJATTR +{ + /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*. + * @remarks We depend on a number of RTFS_ defines to remain unchanged. + * Fortuntately, these are depending on windows, dos and unix + * standard values, so this shouldn't be much of a pain. */ + RTFMODE fMode; + + /** The additional attributes available. */ + SHCLFSOBJATTRADD enmAdditional; + + /** + * Additional attributes. + * + * Unless explicitly specified to an API, the API can provide additional + * data as it is provided by the underlying OS. + */ + union SHCLFSOBJATTRUNION + { + /** Additional Unix Attributes + * These are available when SHCLFSOBJATTRADD is set in fUnix. + */ + struct SHCLFSOBJATTRUNIX + { + /** The user owning the filesystem object (st_uid). + * This field is ~0U if not supported. */ + RTUID uid; + + /** The group the filesystem object is assigned (st_gid). + * This field is ~0U if not supported. */ + RTGID gid; + + /** Number of hard links to this filesystem object (st_nlink). + * This field is 1 if the filesystem doesn't support hardlinking or + * the information isn't available. + */ + uint32_t cHardlinks; + + /** The device number of the device which this filesystem object resides on (st_dev). + * This field is 0 if this information is not available. */ + RTDEV INodeIdDevice; + + /** The unique identifier (within the filesystem) of this filesystem object (st_ino). + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. + * This field is 0 if the information is not available. */ + RTINODE INodeId; + + /** User flags (st_flags). + * This field is 0 if this information is not available. */ + uint32_t fFlags; + + /** The current generation number (st_gen). + * This field is 0 if this information is not available. */ + uint32_t GenerationId; + + /** The device number of a character or block device type object (st_rdev). + * This field is 0 if the file isn't of a character or block device type and + * when the OS doesn't subscribe to the major+minor device idenfication scheme. */ + RTDEV Device; + } Unix; + + /** + * Extended attribute size. + */ + struct SHCLFSOBJATTREASIZE + { + /** Size of EAs. */ + RTFOFF cb; + } EASize; + + /** Padding the structure to a multiple of 8 bytes. */ + uint64_t au64Padding[5]; + } u; +} SHCLFSOBJATTR; +AssertCompileSize(SHCLFSOBJATTR, 48); +/** Pointer to a Shared Clipboard filesystem object attributes structure. */ +typedef SHCLFSOBJATTR *PSHCLFSOBJATTR; +/** Pointer to a const Shared Clipboard filesystem object attributes structure. */ +typedef const SHCLFSOBJATTR *PCSHCLFSOBJATTR; + +/** + * Shared Clipboard file system object information structure. + * + * @sa RTFSOBJINFO + */ +typedef struct _SHCLFSOBJINFO +{ + /** Logical size (st_size). + * For normal files this is the size of the file. + * For symbolic links, this is the length of the path name contained + * in the symbolic link. + * For other objects this fields needs to be specified. + */ + RTFOFF cbObject; + + /** Disk allocation size (st_blocks * DEV_BSIZE). */ + RTFOFF cbAllocated; + + /** Time of last access (st_atime). + * @remarks Here (and other places) we depend on the IPRT timespec to + * remain unchanged. */ + RTTIMESPEC AccessTime; + + /** Time of last data modification (st_mtime). */ + RTTIMESPEC ModificationTime; + + /** Time of last status change (st_ctime). + * If not available this is set to ModificationTime. + */ + RTTIMESPEC ChangeTime; + + /** Time of file birth (st_birthtime). + * If not available this is set to ChangeTime. + */ + RTTIMESPEC BirthTime; + + /** Attributes. */ + SHCLFSOBJATTR Attr; + +} SHCLFSOBJINFO; +AssertCompileSize(SHCLFSOBJINFO, 96); +/** Pointer to a Shared Clipboard filesystem object information structure. */ +typedef SHCLFSOBJINFO *PSHCLFSOBJINFO; +/** Pointer to a const Shared Clipboard filesystem object information + * structure. */ +typedef const SHCLFSOBJINFO *PCSHCLFSOBJINFO; + +/** + * Structure for keeping object open/create parameters. + */ +typedef struct _SHCLOBJOPENCREATEPARMS +{ + /** Path to object to open / create. */ + char *pszPath; + /** Size (in bytes) of path to to object. */ + uint32_t cbPath; + /** SHCL_OBJ_CF_* */ + uint32_t fCreate; + /** + * Attributes of object to open/create and + * returned actual attributes of opened/created object. + */ + SHCLFSOBJINFO ObjInfo; +} SHCLOBJOPENCREATEPARMS, *PSHCLOBJOPENCREATEPARMS; + +/** + * Structure for keeping a reply message. + */ +typedef struct _SHCLREPLY +{ + /** Message type of type VBOX_SHCL_REPLYMSGTYPE_XXX. */ + uint32_t uType; + /** IPRT result of overall operation. Note: int vs. uint32! */ + uint32_t rc; + union + { + struct + { + SHCLTRANSFERSTATUS uStatus; + } TransferStatus; + struct + { + SHCLLISTHANDLE uHandle; + } ListOpen; + struct + { + SHCLLISTHANDLE uHandle; + } ListClose; + struct + { + SHCLOBJHANDLE uHandle; + } ObjOpen; + struct + { + SHCLOBJHANDLE uHandle; + } ObjClose; + } u; + /** Pointer to optional payload. */ + void *pvPayload; + /** Payload size (in bytes). */ + uint32_t cbPayload; +} SHCLREPLY, *PSHCLREPLY; + +struct _SHCLLISTENTRY; +typedef _SHCLLISTENTRY SHCLLISTENTRY; + +/** Defines a single root list entry. Currently the same as a regular list entry. */ +typedef SHCLLISTENTRY SHCLROOTLISTENTRY; +/** Defines a pointer to a single root list entry. Currently the same as a regular list entry pointer. */ +typedef SHCLROOTLISTENTRY *PSHCLROOTLISTENTRY; + +/** + * Structure for keeping Shared Clipboard root list headers. + */ +typedef struct _SHCLROOTLISTHDR +{ + /** Roots listing flags; unused at the moment. */ + uint32_t fRoots; + /** Number of root list entries. */ + uint32_t cRoots; +} SHCLROOTLISTHDR, *PSHCLROOTLISTHDR; + +/** + * Structure for maintaining a Shared Clipboard root list. + */ +typedef struct _SHCLROOTLIST +{ + /** Root list header. */ + SHCLROOTLISTHDR Hdr; + /** Root list entries. */ + SHCLROOTLISTENTRY *paEntries; +} SHCLROOTLIST, *PSHCLROOTLIST; + +/** + * Structure for maintaining Shared Clipboard list open paramters. + */ +typedef struct _SHCLLISTOPENPARMS +{ + /** Listing flags (see VBOX_SHCL_LIST_FLAG_XXX). */ + uint32_t fList; + /** Size (in bytes) of the filter string. */ + uint32_t cbFilter; + /** Filter string. DOS wilcard-style. */ + char *pszFilter; + /** Size (in bytes) of the listing path. */ + uint32_t cbPath; + /** Listing path (absolute). If empty or NULL the listing's root path will be opened. */ + char *pszPath; +} SHCLLISTOPENPARMS, *PSHCLLISTOPENPARMS; + +/** + * Structure for keeping a Shared Clipboard list header. + */ +typedef struct _SHCLLISTHDR +{ + /** Feature flag(s). Not being used atm. */ + uint32_t fFeatures; + /** Total objects returned. */ + uint64_t cTotalObjects; + /** Total size (in bytes) returned. */ + uint64_t cbTotalSize; +} SHCLLISTHDR, *PSHCLLISTHDR; + +/** + * Structure for a Shared Clipboard list entry. + */ +typedef struct _SHCLLISTENTRY +{ + /** Entry name. */ + char *pszName; + /** Size (in bytes) of entry name. */ + uint32_t cbName; + /** Information flag(s). */ + uint32_t fInfo; + /** Size (in bytes) of the actual list entry. */ + uint32_t cbInfo; + /** Data of the actual list entry. */ + void *pvInfo; +} SHCLLISTENTRY, *PSHCLLISTENTRY; + +/** Maximum length (in UTF-8 characters) of a list entry name. */ +#define SHCLLISTENTRY_MAX_NAME RTPATH_MAX /** @todo Improve this to be more dynamic. */ + +/** + * Structure for maintaining a Shared Clipboard list. + */ +typedef struct _SHCLLIST +{ + /** List header. */ + SHCLLISTHDR Hdr; + /** List entries. */ + SHCLROOTLISTENTRY *paEntries; +} SHCLLIST, *PSHCLLIST; + +/** + * Structure for keeping a Shared Clipboard object data chunk. + */ +typedef struct _SHCLOBJDATACHUNK +{ + /** Handle of object this data chunk is related to. */ + uint64_t uHandle; + /** Pointer to actual data chunk. */ + void *pvData; + /** Size (in bytes) of data chunk. */ + uint32_t cbData; +} SHCLOBJDATACHUNK, *PSHCLOBJDATACHUNK; + +/** + * Structure for handling a single transfer object context. + */ +typedef struct _SHCLCLIENTTRANSFEROBJCTX +{ + SHCLTRANSFER *pTransfer; + SHCLOBJHANDLE uHandle; +} SHCLCLIENTTRANSFEROBJCTX, *PSHCLCLIENTTRANSFEROBJCTX; + +typedef struct _SHCLTRANSFEROBJSTATE +{ + /** How many bytes were processed (read / write) so far. */ + uint64_t cbProcessed; +} SHCLTRANSFEROBJSTATE, *PSHCLTRANSFEROBJSTATE; + +typedef struct _SHCLTRANSFEROBJ +{ + SHCLOBJHANDLE uHandle; + char *pszPathAbs; + SHCLFSOBJINFO objInfo; + SHCLSOURCE enmSource; + SHCLTRANSFEROBJSTATE State; +} SHCLTRANSFEROBJ, *PSHCLTRANSFEROBJ; + +/** + * Enumeration for specifying a Shared Clipboard object type. + */ +typedef enum _SHCLOBJTYPE +{ + /** Invalid object type. */ + SHCLOBJTYPE_INVALID = 0, + /** Object is a directory. */ + SHCLOBJTYPE_DIRECTORY, + /** Object is a file. */ + SHCLOBJTYPE_FILE, + /** Object is a symbolic link. */ + SHCLOBJTYPE_SYMLINK, + /** The usual 32-bit hack. */ + SHCLOBJTYPE_32BIT_SIZE_HACK = 0x7fffffff +} SHCLOBJTYPE; + +/** + * Structure for keeping transfer list handle information. + * This is using to map own (local) handles to the underlying file system. + */ +typedef struct _SHCLLISTHANDLEINFO +{ + /** The list node. */ + RTLISTNODE Node; + /** The list's handle. */ + SHCLLISTHANDLE hList; + /** Type of list handle. */ + SHCLOBJTYPE enmType; + /** Absolute local path of the list object. */ + char *pszPathLocalAbs; + union + { + /** Local data, based on enmType. */ + struct + { + union + { + RTDIR hDir; + RTFILE hFile; + }; + } Local; + } u; +} SHCLLISTHANDLEINFO, *PSHCLLISTHANDLEINFO; + +/** + * Structure for keeping transfer object handle information. + * This is using to map own (local) handles to the underlying file system. + */ +typedef struct _SHCLOBJHANDLEINFO +{ + /** The list node. */ + RTLISTNODE Node; + /** The object's handle. */ + SHCLOBJHANDLE hObj; + /** Type of object handle. */ + SHCLOBJTYPE enmType; + /** Absolute local path of the object. */ + char *pszPathLocalAbs; + union + { + /** Local data, based on enmType. */ + struct + { + union + { + RTDIR hDir; + RTFILE hFile; + }; + } Local; + } u; +} SHCLOBJHANDLEINFO, *PSHCLOBJHANDLEINFO; + +/** + * Structure for keeping a single root list entry. + */ +typedef struct _SHCLLISTROOT +{ + /** The list node. */ + RTLISTNODE Node; + /** Absolute path of entry. */ + char *pszPathAbs; +} SHCLLISTROOT, *PSHCLLISTROOT; + +/** + * Structure for maintaining an Shared Clipboard transfer state. + * Everything in here will be part of a saved state (later). + */ +typedef struct _SHCLTRANSFERSTATE +{ + /** The transfer's (local) ID. */ + SHCLTRANSFERID uID; + /** The transfer's current status. */ + SHCLTRANSFERSTATUS enmStatus; + /** The transfer's direction, seen from the perspective who created the transfer. */ + SHCLTRANSFERDIR enmDir; + /** The transfer's source, seen from the perspective who created the transfer. */ + SHCLSOURCE enmSource; +} SHCLTRANSFERSTATE, *PSHCLTRANSFERSTATE; + +/** + * Structure maintaining clipboard transfer provider context data. + * This is handed in to the provider interface implementations. + */ +typedef struct _SHCLTXPROVIDERCTX +{ + /** Pointer to the related Shared Clipboard transfer. */ + PSHCLTRANSFER pTransfer; + /** User-defined data pointer. Can be NULL if not needed. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTXPROVIDERCTX, *PSHCLTXPROVIDERCTX; + +struct SHCLTRANSFERCTX; +typedef struct SHCLTRANSFERCTX *PSHCLTRANSFERCTX; + +/** + * Shared Clipboard transfer provider interface table. + * + * A transfer provider inteface implementation realizes all low level functions + * needed for making a Shared Clipboard transfer happen. + */ +typedef struct _SHCLTXPROVIDERIFACE +{ + DECLCALLBACKMEMBER(int, pfnRootsGet,(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)); + DECLCALLBACKMEMBER(int, pfnListOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)); + DECLCALLBACKMEMBER(int, pfnListClose,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)); + DECLCALLBACKMEMBER(int, pfnListHdrRead,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)); + DECLCALLBACKMEMBER(int, pfnListHdrWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)); + DECLCALLBACKMEMBER(int, pfnListEntryRead,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)); + DECLCALLBACKMEMBER(int, pfnListEntryWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)); + DECLCALLBACKMEMBER(int, pfnObjOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)); + DECLCALLBACKMEMBER(int, pfnObjClose,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)); + DECLCALLBACKMEMBER(int, pfnObjRead,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, + uint32_t fFlags, uint32_t *pcbRead)); + DECLCALLBACKMEMBER(int, pfnObjWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, + uint32_t fFlags, uint32_t *pcbWritten)); +} SHCLTXPROVIDERIFACE, *PSHCLTXPROVIDERIFACE; + +/** + * Structure for the Shared Clipboard transfer provider creation context. + */ +typedef struct _SHCLTXPROVIDERCREATIONCTX +{ + /** Specifies what the source of the provider is. */ + SHCLSOURCE enmSource; + /** The provider interface table. */ + SHCLTXPROVIDERIFACE Interface; + /** User-provided callback data. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTXPROVIDERCREATIONCTX, *PSHCLTXPROVIDERCREATIONCTX; + +/** + * Structure maintaining clipboard transfer callback context data. + */ +typedef struct _SHCLTRANSFERCALLBACKCTX +{ + /** Pointer to the related Shared Clipboard transfer. */ + PSHCLTRANSFER pTransfer; + /** User-defined data pointer. Can be NULL if not needed. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTRANSFERCALLBACKCTX, *PSHCLTRANSFERCALLBACKCTX; + +/** + * Shared Clipboard transfer callback table. + * + * All callbacks are optional and can provide additional information / feedback to a frontend. + */ +typedef struct _SHCLTRANSFERCALLBACKTABLE +{ + /** + * Called when the transfer gets initialized. + * + * @param pCbCtx Pointer to callback context to use. + */ + DECLCALLBACKMEMBER(int, pfnOnInitialize,(PSHCLTRANSFERCALLBACKCTX pCbCtx)); + /** + * Called before the transfer will be started. + * + * @param pCbCtx Pointer to callback context to use. + */ + DECLCALLBACKMEMBER(int, pfnOnStart,(PSHCLTRANSFERCALLBACKCTX pCbCtx)); + /** + * Called when the transfer has been complete. + * + * @param pCbCtx Pointer to callback context to use. + * @param rcCompletion Completion result. + * VERR_CANCELED if transfer has been canceled. + */ + DECLCALLBACKMEMBER(void, pfnOnCompleted,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion)); + /** + * Called when transfer resulted in an unrecoverable error. + * + * @param pCbCtx Pointer to callback context to use. + * @param rcError Error reason, IPRT-style. + */ + DECLCALLBACKMEMBER(void, pfnOnError,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError)); + /** + * Called when transfer got registered to a transfer context. + * + * @param pCbCtx Pointer to callback context to use. + * @param pTransferCtx Transfer context transfer was registered to. + */ + DECLCALLBACKMEMBER(void, pfnOnRegistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)); + /** + * Called when transfer got unregistered from a transfer context. + * + * @param pCbCtx Pointer to callback context to use. + * @param pTransferCtx Transfer context transfer was unregistered from. + */ + DECLCALLBACKMEMBER(void, pfnOnUnregistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)); + + /** User-provided callback data. Can be NULL if not used. */ + void *pvUser; + /** Size (in bytes) of data pointer at \a pvUser. */ + size_t cbUser; +} SHCLTRANSFERCALLBACKTABLE, *PSHCLTRANSFERCALLBACKTABLE; + +/** + * Structure for thread-related members for a single Shared Clipboard transfer. + */ +typedef struct _SHCLTRANSFERTHREAD +{ + /** Thread handle for the reading / writing thread. + * Can be NIL_RTTHREAD if not being used. */ + RTTHREAD hThread; + /** Thread started indicator. */ + volatile bool fStarted; + /** Thread stop flag. */ + volatile bool fStop; + /** Thread cancelled flag / indicator. */ + volatile bool fCancelled; +} SHCLTRANSFERTHREAD, *PSHCLTRANSFERTHREAD; + +/** + * A single Shared Clipboard transfer. + * + ** @todo Not yet thread safe. + */ +typedef struct SHCLTRANSFER +{ + /** The node member for using this struct in a RTList. */ + RTLISTNODE Node; + /** The transfer's state (for SSM, later). */ + SHCLTRANSFERSTATE State; + /** Absolute path to root entries. */ + char *pszPathRootAbs; + /** Timeout (in ms) for waiting of events. Default is 30s. */ + RTMSINTERVAL uTimeoutMs; + /** Maximum data chunk size (in bytes) to transfer. Default is 64K. */ + uint32_t cbMaxChunkSize; + /** The transfer's own event source. */ + SHCLEVENTSOURCE Events; + /** Current number of concurrent list handles. */ + uint32_t cListHandles; + /** Maximum number of concurrent list handles. */ + uint32_t cMaxListHandles; + /** Next upcoming list handle. */ + SHCLLISTHANDLE uListHandleNext; + /** List of all list handles elated to this transfer. */ + RTLISTANCHOR lstList; + /** Number of root entries in list. */ + uint64_t cRoots; + /** List of root entries of this transfer. */ + RTLISTANCHOR lstRoots; + /** Current number of concurrent object handles. */ + uint32_t cObjHandles; + /** Maximum number of concurrent object handles. */ + uint32_t cMaxObjHandles; + /** Next upcoming object handle. */ + SHCLOBJHANDLE uObjHandleNext; + /** Map of all objects handles related to this transfer. */ + RTLISTANCHOR lstObj; + /** The transfer's own provider context. */ + SHCLTXPROVIDERCTX ProviderCtx; + /** The transfer's provider interface. */ + SHCLTXPROVIDERIFACE ProviderIface; + /** The transfer's callback context. */ + SHCLTRANSFERCALLBACKCTX CallbackCtx; + /** The transfer's callback table. */ + SHCLTRANSFERCALLBACKTABLE Callbacks; + /** Opaque pointer to implementation-specific parameters. */ + void *pvUser; + /** Size (in bytes) of implementation-specific parameters. */ + size_t cbUser; + /** Contains thread-related attributes. */ + SHCLTRANSFERTHREAD Thread; + /** Critical section for serializing access. */ + RTCRITSECT CritSect; +} SHCLTRANSFER, *PSHCLTRANSFER; + +/** + * Structure for keeping an Shared Clipboard transfer status report. + */ +typedef struct _SHCLTRANSFERREPORT +{ + /** Actual status to report. */ + SHCLTRANSFERSTATUS uStatus; + /** Result code (rc) to report; might be unused / invalid, based on enmStatus. */ + int rc; + /** Reporting flags. Currently unused and must be 0. */ + uint32_t fFlags; +} SHCLTRANSFERREPORT, *PSHCLTRANSFERREPORT; + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +typedef struct _SHCLHTTPSERVER +{ + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** Handle of the HTTP server instance. */ + RTHTTPSERVER hHTTPServer; + /** Port number the HTTP server is running on. 0 if not running. */ + uint16_t uPort; + /** List of registered HTTP transfers. */ + RTLISTANCHOR lstTransfers; + /** Number of registered HTTP transfers. */ + uint32_t cTransfers; + /** Cached response data. */ + RTHTTPSERVERRESP Resp; +} SHCLHTTPSERVER; +typedef SHCLHTTPSERVER *PSHCLHTTPSERVER; + +typedef struct _SHCLHTTPCONTEXT +{ + /** HTTP server instance data. */ + SHCLHTTPSERVER HttpServer; +} SHCLHTTPCONTEXT; +typedef SHCLHTTPCONTEXT *PSHCLHTTPCONTEXT; + +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ + +/** + * Structure for keeping Shared Clipboard transfer context around. + */ +struct SHCLTRANSFERCTX +{ + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** List of transfers. */ + RTLISTANCHOR List; + /** Transfer ID allocation bitmap; clear bits are free, set bits are busy. */ + uint64_t bmTransferIds[VBOX_SHCL_MAX_TRANSFERS / sizeof(uint64_t) / 8]; + /** Number of running (concurrent) transfers. */ + uint16_t cRunning; + /** Maximum Number of running (concurrent) transfers. */ + uint16_t cMaxRunning; + /** Number of total transfers (in list). */ + uint16_t cTransfers; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP + /** HTTP server instance for this transfer context. */ + SHCLHTTPSERVER HttpServer; +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ +}; + +int ShClTransferObjCtxInit(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); +void ShClTransferObjCtxDestroy(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); +bool ShClTransferObjCtxIsValid(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); + +int ShClTransferObjHandleInfoInit(PSHCLOBJHANDLEINFO pInfo); +void ShClTransferObjHandleInfoDestroy(PSHCLOBJHANDLEINFO pInfo); + +int ShClTransferObjOpenParmsInit(PSHCLOBJOPENCREATEPARMS pParms); +int ShClTransferObjOpenParmsCopy(PSHCLOBJOPENCREATEPARMS pParmsDst, PSHCLOBJOPENCREATEPARMS pParmsSrc); +void ShClTransferObjOpenParmsDestroy(PSHCLOBJOPENCREATEPARMS pParms); + +int ShClTransferObjOpen(PSHCLTRANSFER pTransfer, PSHCLOBJOPENCREATEPARMS pOpenCreateParms, PSHCLOBJHANDLE phObj); +int ShClTransferObjClose(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj); +int ShClTransferObjRead(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbRead); +int ShClTransferObjWrite(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbWritten); + +PSHCLOBJDATACHUNK ShClTransferObjDataChunkDup(PSHCLOBJDATACHUNK pDataChunk); +void ShClTransferObjDataChunkDestroy(PSHCLOBJDATACHUNK pDataChunk); +void ShClTransferObjDataChunkFree(PSHCLOBJDATACHUNK pDataChunk); + +int ShClTransferCreate(PSHCLTRANSFER *ppTransfer); +int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource); +int ShClTransferDestroy(PSHCLTRANSFER pTransfer); + +int ShClTransferListOpen(PSHCLTRANSFER pTransfer, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList); +int ShClTransferListClose(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList); +int ShClTransferListGetHeader(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTHDR pHdr); +PSHCLTRANSFEROBJ ShClTransferListGetObj(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, uint64_t uIdx); +int ShClTransferListRead(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry); +int ShClTransferListWrite(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry); +bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList); + +int ShClPathSanitizeFilename(char *pszPath, size_t cbPath); +int ShClPathSanitize(char *pszPath, size_t cbPath); + +PSHCLROOTLIST ShClTransferRootListAlloc(void); +void ShClTransferRootListFree(PSHCLROOTLIST pRootList); + +PSHCLROOTLISTHDR ShClTransferRootListHdrDup(PSHCLROOTLISTHDR pRoots); +int ShClTransferRootListHdrInit(PSHCLROOTLISTHDR pRoots); +void ShClTransferRootListHdrDestroy(PSHCLROOTLISTHDR pRoots); + +int ShClTransferRootListEntryCopy(PSHCLROOTLISTENTRY pDst, PSHCLROOTLISTENTRY pSrc); +int ShClTransferRootListEntryInit(PSHCLROOTLISTENTRY pRootListEntry); +void ShClTransferRootListEntryDestroy(PSHCLROOTLISTENTRY pRootListEntry); +PSHCLROOTLISTENTRY ShClTransferRootListEntryDup(PSHCLROOTLISTENTRY pRootListEntry); + +int ShClTransferListHandleInfoInit(PSHCLLISTHANDLEINFO pInfo); +void ShClTransferListHandleInfoDestroy(PSHCLLISTHANDLEINFO pInfo); + +int ShClTransferListHdrAlloc(PSHCLLISTHDR *ppListHdr); +void ShClTransferListHdrFree(PSHCLLISTHDR pListHdr); +PSHCLLISTHDR ShClTransferListHdrDup(PSHCLLISTHDR pListHdr); +int ShClTransferListHdrInit(PSHCLLISTHDR pListHdr); +void ShClTransferListHdrDestroy(PSHCLLISTHDR pListHdr); +void ShClTransferListHdrReset(PSHCLLISTHDR pListHdr); +bool ShClTransferListHdrIsValid(PSHCLLISTHDR pListHdr); + +int ShClTransferListOpenParmsCopy(PSHCLLISTOPENPARMS pDst, PSHCLLISTOPENPARMS pSrc); +PSHCLLISTOPENPARMS ShClTransferListOpenParmsDup(PSHCLLISTOPENPARMS pParms); +int ShClTransferListOpenParmsInit(PSHCLLISTOPENPARMS pParms); +void ShClTransferListOpenParmsDestroy(PSHCLLISTOPENPARMS pParms); + +int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry); +void ShClTransferListEntryFree(PSHCLLISTENTRY pListEntry); +int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc); +PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry); +int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry); +void ShClTransferListEntryDestroy(PSHCLLISTENTRY pListEntry); +bool ShClTransferListEntryIsValid(PSHCLLISTENTRY pListEntry); + +void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst, PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc); +void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, PSHCLTRANSFERCALLBACKTABLE pCallbacks); +int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDERCREATIONCTX pCreationCtx); +int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots); +void ShClTransferReset(PSHCLTRANSFER pTransfer); + +uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer); +int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer, uint64_t uIndex, PSHCLROOTLISTENTRY pEntry); +int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList); + +SHCLTRANSFERID ShClTransferGetID(PSHCLTRANSFER pTransfer); +SHCLTRANSFERDIR ShClTransferGetDir(PSHCLTRANSFER pTransfer); +SHCLSOURCE ShClTransferGetSource(PSHCLTRANSFER pTransfer); +SHCLTRANSFERSTATUS ShClTransferGetStatus(PSHCLTRANSFER pTransfer); +int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser); +int ShClTransferStart(PSHCLTRANSFER pTransfer); + +int ShClTransferCtxInit(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxDestroy(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxReset(PSHCLTRANSFERCTX pTransferCtx); +PSHCLTRANSFER ShClTransferCtxGetTransferById(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID); +PSHCLTRANSFER ShClTransferCtxGetTransferByIndex(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx); +uint32_t ShClTransferCtxGetRunningTransfers(PSHCLTRANSFERCTX pTransferCtx); +uint32_t ShClTransferCtxGetTotalTransfers(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxCleanup(PSHCLTRANSFERCTX pTransferCtx); +bool ShClTransferCtxTransfersMaximumReached(PSHCLTRANSFERCTX pTransferCtx); +int ShClTransferCtxTransferRegister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID *pidTransfer); +int ShClTransferCtxTransferRegisterById(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID idTransfer); +int ShClTransferCtxTransferUnregister(PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +int ShClHttpTransferRegister(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer); +int ShClHttpTransferUnregister(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer); + +int ShClTransferHttpServerCreate(PSHCLHTTPSERVER pSrv, uint16_t *puPort); +int ShClTransferHttpServerCreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort); +int ShClTransferHttpServerDestroy(PSHCLHTTPSERVER pSrv); +void ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv); +int ShClTransferHttpServerRegisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer); +int ShClTransferHttpServerUnregisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer); +bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); +uint16_t ShClTransferHttpServerGetPort(PSHCLHTTPSERVER pSrv); +uint32_t ShClTransferHttpServerGetTransferCount(PSHCLHTTPSERVER pSrv); +char *ShClTransferHttpServerGetAddressA(PSHCLHTTPSERVER pSrv); +char *ShClTransferHttpServerGetUrlA(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); +bool ShClTransferHttpServerIsRunning(PSHCLHTTPSERVER pSrv); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ + +void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc); + +bool ShClMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax); +bool ShClMIMENeedsCache(const char *pcszFormat, size_t cchFormatMax); + +const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus); + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h */ diff --git a/include/VBox/GuestHost/SharedClipboard-win.h b/include/VBox/GuestHost/SharedClipboard-win.h new file mode 100644 index 00000000..730285c4 --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-win.h @@ -0,0 +1,419 @@ +/** @file + * Shared Clipboard - Common Guest and Host Code, for Windows OSes. + */ + +/* + * 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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_win_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/critsect.h> +#include <iprt/types.h> +#include <iprt/win/windows.h> + +#include <VBox/GuestHost/SharedClipboard.h> + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include <vector> + +# include <iprt/cpp/ministring.h> /* For RTCString. */ +# include <iprt/win/shlobj.h> /* For DROPFILES and friends. */ +# include <VBox/com/string.h> /* For Utf8Str. */ +# include <oleidl.h> + +# include <VBox/GuestHost/SharedClipboard-transfers.h> + +using namespace com; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +#ifndef WM_CLIPBOARDUPDATE +# define WM_CLIPBOARDUPDATE 0x031D +#endif + +#define SHCL_WIN_WNDCLASS_NAME "VBoxSharedClipboardClass" + +/** See: https://docs.microsoft.com/en-us/windows/desktop/dataxchg/html-clipboard-format + * Do *not* change the name, as this will break compatbility with other (legacy) applications! */ +#define SHCL_WIN_REGFMT_HTML "HTML Format" + +/** Default timeout (in ms) for passing down messages down the clipboard chain. */ +#define SHCL_WIN_CBCHAIN_TIMEOUT_MS 5000 + +/** Reports clipboard formats. */ +#define SHCL_WIN_WM_REPORT_FORMATS WM_USER +/** Reads data from the clipboard and sends it to the destination. */ +#define SHCL_WIN_WM_READ_DATA WM_USER + 1 +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** Starts a transfer on the guest. + * This creates the necessary IDataObject in the matching window thread. */ +# define SHCL_WIN_WM_TRANSFER_START WM_USER + 2 +#endif + +/* Dynamically load clipboard functions from User32.dll. */ +typedef BOOL WINAPI FNADDCLIPBOARDFORMATLISTENER(HWND); +typedef FNADDCLIPBOARDFORMATLISTENER *PFNADDCLIPBOARDFORMATLISTENER; + +typedef BOOL WINAPI FNREMOVECLIPBOARDFORMATLISTENER(HWND); +typedef FNREMOVECLIPBOARDFORMATLISTENER *PFNREMOVECLIPBOARDFORMATLISTENER; + +/** + * Structure for keeping function pointers for the new clipboard API. + * If the new API is not available, those function pointer are NULL. + */ +typedef struct _SHCLWINAPINEW +{ + PFNADDCLIPBOARDFORMATLISTENER pfnAddClipboardFormatListener; + PFNREMOVECLIPBOARDFORMATLISTENER pfnRemoveClipboardFormatListener; +} SHCLWINAPINEW, *PSHCLWINAPINEW; + +/** + * Structure for keeping variables which are needed to drive the old clipboard API. + */ +typedef struct _SHCLWINAPIOLD +{ + /** Timer ID for the refresh timer. */ + UINT timerRefresh; + /** Whether "pinging" the clipboard chain currently is in progress or not. */ + bool fCBChainPingInProcess; +} SHCLWINAPIOLD, *PSHCLWINAPIOLD; + +/** + * Structure for maintaining a Shared Clipboard context on Windows platforms. + */ +typedef struct _SHCLWINCTX +{ + /** Critical section to serialize access. */ + RTCRITSECT CritSect; + /** Window handle of our (invisible) clipbaord window. */ + HWND hWnd; + /** Window handle which is next to us in the clipboard chain. */ + HWND hWndNextInChain; + /** Window handle of the clipboard owner *if* we are the owner. + * @todo r=bird: Ignore the misleading statement above. This is only set to + * NULL by the initialization code and then it's set to the clipboard owner + * after we announce data to the clipboard. So, essentially this will be our + * windows handle or NULL. End of story. */ + HWND hWndClipboardOwnerUs; + /** Structure for maintaining the new clipboard API. */ + SHCLWINAPINEW newAPI; + /** Structure for maintaining the old clipboard API. */ + SHCLWINAPIOLD oldAPI; +} SHCLWINCTX, *PSHCLWINCTX; + +int SharedClipboardWinOpen(HWND hWnd); +int SharedClipboardWinClose(void); +int SharedClipboardWinClear(void); + +int SharedClipboardWinCtxInit(PSHCLWINCTX pWinCtx); +void SharedClipboardWinCtxDestroy(PSHCLWINCTX pWinCtx); + +int SharedClipboardWinCheckAndInitNewAPI(PSHCLWINAPINEW pAPI); +bool SharedClipboardWinIsNewAPI(PSHCLWINAPINEW pAPI); + +int SharedClipboardWinDataWrite(UINT cfFormat, void *pvData, uint32_t cbData); + +int SharedClipboardWinChainAdd(PSHCLWINCTX pCtx); +int SharedClipboardWinChainRemove(PSHCLWINCTX pCtx); +VOID CALLBACK SharedClipboardWinChainPingProc(HWND hWnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult) RT_NOTHROW_DEF; +LRESULT SharedClipboardWinChainPassToNext(PSHCLWINCTX pWinCtx, UINT msg, WPARAM wParam, LPARAM lParam); + +SHCLFORMAT SharedClipboardWinClipboardFormatToVBox(UINT uFormat); +int SharedClipboardWinGetFormats(PSHCLWINCTX pCtx, PSHCLFORMATS pfFormats); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +int SharedClipboardWinGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +int SharedClipboardWinDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList); +#endif + +int SharedClipboardWinGetCFHTMLHeaderValue(const char *pszSrc, const char *pszOption, uint32_t *puValue); +bool SharedClipboardWinIsCFHTML(const char *pszSource); +int SharedClipboardWinConvertCFHTMLToMIME(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pcbOutput); +int SharedClipboardWinConvertMIMEToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput); + +LRESULT SharedClipboardWinHandleWMChangeCBChain(PSHCLWINCTX pWinCtx, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +int SharedClipboardWinHandleWMDestroy(PSHCLWINCTX pWinCtx); +int SharedClipboardWinHandleWMRenderAllFormats(PSHCLWINCTX pWinCtx, HWND hWnd); +int SharedClipboardWinHandleWMTimer(PSHCLWINCTX pWinCtx); + +int SharedClipboardWinClearAndAnnounceFormats(PSHCLWINCTX pWinCtx, SHCLFORMATS fFormats, HWND hWnd); +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +int SharedClipboardWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +void SharedClipboardWinTransferDestroy(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +#endif + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +class SharedClipboardTransferList; +# ifndef FILEGROUPDESCRIPTOR +class FILEGROUPDESCRIPTOR; +# endif + +class SharedClipboardWinDataObject : public IDataObject //, public IDataObjectAsyncCapability +{ +public: + + enum Status + { + /** The object is uninitialized (not ready). */ + Uninitialized = 0, + /** The object is initialized and ready to use. */ + Initialized, + /** The operation has been successfully completed. */ + Completed, + /** The operation has been canceled. */ + Canceled, + /** An (unrecoverable) error occurred. */ + Error + }; + +public: + + SharedClipboardWinDataObject(PSHCLTRANSFER pTransfer, + LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0); + virtual ~SharedClipboardWinDataObject(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IDataObject methods. */ + + STDMETHOD(GetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium); + STDMETHOD(GetDataHere)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium); + STDMETHOD(QueryGetData)(LPFORMATETC pFormatEtc); + STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pFormatEct, LPFORMATETC pFormatEtcOut); + STDMETHOD(SetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease); + STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc); + STDMETHOD(DAdvise)(LPFORMATETC pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection); + STDMETHOD(DUnadvise)(DWORD dwConnection); + STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppEnumAdvise); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC +public: /* IDataObjectAsyncCapability methods. */ + + STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx* pbcReserved, DWORD dwEffects); + STDMETHOD(GetAsyncMode)(BOOL* pfIsOpAsync); + STDMETHOD(InOperation)(BOOL* pfInAsyncOp); + STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync); + STDMETHOD(StartOperation)(IBindCtx* pbcReserved); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */ + +public: + + int Init(void); + void OnTransferComplete(int rc = VINF_SUCCESS); + void OnTransferCanceled(); + +public: + + static DECLCALLBACK(int) readThread(RTTHREAD ThreadSelf, void *pvUser); + + static void logFormat(CLIPFORMAT fmt); + +protected: + + static int Thread(RTTHREAD hThread, void *pvUser); + + int readDir(PSHCLTRANSFER pTransfer, const Utf8Str &strPath); + + int copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal); + int createFileGroupDescriptorFromTransfer(PSHCLTRANSFER pTransfer, + bool fUnicode, HGLOBAL *phGlobal); + + bool lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex); + void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL, + LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL); +protected: + + /** + * Structure for keeping a single file system object entry. + */ + struct FSOBJENTRY + { + /** Relative path of the object. */ + Utf8Str strPath; + /** Related (cached) object information. */ + SHCLFSOBJINFO objInfo; + }; + + /** Vector containing file system objects with its (cached) objection information. */ + typedef std::vector<FSOBJENTRY> FsObjEntryList; + + /** The object's current status. */ + Status m_enmStatus; + /** The object's current reference count. */ + LONG m_lRefCount; + /** How many formats have been registered. */ + ULONG m_cFormats; + LPFORMATETC m_pFormatEtc; + LPSTGMEDIUM m_pStgMedium; + /** Pointer to the associated transfer object being handled. */ + PSHCLTRANSFER m_pTransfer; + /** Current stream object being used. */ + IStream *m_pStream; + /** Current object index being handled by the data object. + * This is needed to create the next IStream object for e.g. the next upcoming file/dir/++ in the transfer. */ + ULONG m_uObjIdx; + /** List of (cached) file system objects. */ + FsObjEntryList m_lstEntries; + /** Whether the transfer thread is running. */ + bool m_fRunning; + /** Event being triggered when reading the transfer list been completed. */ + RTSEMEVENT m_EventListComplete; + /** Event being triggered when the transfer has been completed. */ + RTSEMEVENT m_EventTransferComplete; + /** Registered format for CFSTR_FILEDESCRIPTORA. */ + UINT m_cfFileDescriptorA; + /** Registered format for CFSTR_FILEDESCRIPTORW. */ + UINT m_cfFileDescriptorW; + /** Registered format for CFSTR_FILECONTENTS. */ + UINT m_cfFileContents; + /** Registered format for CFSTR_PERFORMEDDROPEFFECT. */ + UINT m_cfPerformedDropEffect; +}; + +class SharedClipboardWinEnumFormatEtc : public IEnumFORMATETC +{ +public: + + SharedClipboardWinEnumFormatEtc(LPFORMATETC pFormatEtc, ULONG cFormats); + virtual ~SharedClipboardWinEnumFormatEtc(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IEnumFORMATETC methods. */ + + STDMETHOD(Next)(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched); + STDMETHOD(Skip)(ULONG cFormats); + STDMETHOD(Reset)(void); + STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc); + +public: + + static void CopyFormat(LPFORMATETC pFormatDest, LPFORMATETC pFormatSource); + static HRESULT CreateEnumFormatEtc(UINT cFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc); + +private: + + LONG m_lRefCount; + ULONG m_nIndex; + ULONG m_nNumFormats; + LPFORMATETC m_pFormatEtc; +}; + +/** + * Own IStream implementation to implement file-based clipboard operations + * through HGCM. Needed on Windows hosts and guests. + */ +class SharedClipboardWinStreamImpl : public IStream +{ +public: + + SharedClipboardWinStreamImpl(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, + const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo); + virtual ~SharedClipboardWinStreamImpl(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IStream methods. */ + + STDMETHOD(Clone)(IStream** ppStream); + STDMETHOD(Commit)(DWORD dwFrags); + STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten); + STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,DWORD dwFlags); + STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead); + STDMETHOD(Revert)(void); + STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos); + STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize); + STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags); + STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags); + STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead); + +public: /* Own methods. */ + + static HRESULT Create(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, const Utf8Str &strPath, + PSHCLFSOBJINFO pObjInfo, IStream **ppStream); +private: + + /** Pointer to the parent data object. */ + SharedClipboardWinDataObject *m_pParent; + /** The stream object's current reference count. */ + LONG m_lRefCount; + /** Pointer to the associated Shared Clipboard transfer. */ + PSHCLTRANSFER m_pTransfer; + /** The object handle to use. */ + SHCLOBJHANDLE m_hObj; + /** Object path. */ + Utf8Str m_strPath; + /** (Cached) object information. */ + SHCLFSOBJINFO m_objInfo; + /** Number of bytes already processed. */ + uint64_t m_cbProcessed; + /** Whether this object already is in completed state or not. */ + bool m_fIsComplete; +}; + +/** + * Class for Windows-specifics for maintaining a single Shared Clipboard transfer. + * Set as pvUser / cbUser in SHCLTRANSFERCTX. + */ +class SharedClipboardWinTransferCtx +{ +public: + SharedClipboardWinTransferCtx() + : pDataObj(NULL) { } + + virtual ~SharedClipboardWinTransferCtx() + { + if (pDataObj) + delete pDataObj; + } + + /** Pointer to data object to use for this transfer. + * Can be NULL if not being used. */ + SharedClipboardWinDataObject *pDataObj; +}; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_win_h */ + diff --git a/include/VBox/GuestHost/SharedClipboard-x11.h b/include/VBox/GuestHost/SharedClipboard-x11.h new file mode 100644 index 00000000..5dd25a0e --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-x11.h @@ -0,0 +1,187 @@ +/** @file + * Shared Clipboard - Common X11 code. + */ + +/* + * 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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <X11/Intrinsic.h> + +#include <iprt/thread.h> + +#include <VBox/GuestHost/SharedClipboard.h> +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include <VBox/GuestHost/SharedClipboard-transfers.h> +#endif + +/** + * The maximum number of simultaneous connections to shared clipboard service. + * This constant limits amount of GUEST -> HOST connections to shared clipboard host service + * for X11 host only. Once amount of connections reaches this number, all the + * further attempts to CONNECT will be dropped on an early stage. Possibility to connect + * is available again after one of existing connections is closed by DISCONNECT call. + */ +#define VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX (20) + +/** Enables the Xt busy / update handling. */ +#define VBOX_WITH_SHARED_CLIPBOARD_XT_BUSY 1 + +/** + * Enumeration for all clipboard formats which we support on X11. + */ +typedef enum _SHCLX11FMT +{ + SHCLX11FMT_INVALID = 0, + SHCLX11FMT_TARGETS, + SHCLX11FMT_TEXT, /* Treat this as UTF-8, but it may really be ascii */ + SHCLX11FMT_UTF8, + SHCLX11FMT_BMP, + SHCLX11FMT_HTML +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + , SHCLX11FMT_URI_LIST +#endif +} SHCLX11FMT; + +/** + * The table maps X11 names to data formats + * and to the corresponding VBox clipboard formats. + */ +typedef struct SHCLX11FMTTABLE +{ + /** The X11 atom name of the format (several names can match one format). */ + const char *pcszAtom; + /** The format corresponding to the name. */ + SHCLX11FMT enmFmtX11; + /** The corresponding VBox clipboard format. */ + SHCLFORMAT uFmtVBox; +} SHCLX11FMTTABLE; + +#define NIL_CLIPX11FORMAT 0 + +/** Defines an index of the X11 clipboad format table. */ +typedef unsigned SHCLX11FMTIDX; + +/** + * Structure for maintaining a Shared Clipboard context on X11 platforms. + */ +typedef struct _SHCLX11CTX +{ + /** Opaque data structure describing the front-end. */ + PSHCLCONTEXT pFrontend; + /** Our callback table to use. */ + SHCLCALLBACKS Callbacks; + /** Is an X server actually available? */ + bool fHaveX11; + /** The X Toolkit application context structure. */ + XtAppContext pAppContext; + /** We have a separate thread to wait for window and clipboard events. */ + RTTHREAD Thread; + /** Flag indicating that the thread is in a started state. */ + bool fThreadStarted; + /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */ + Widget pWidget; + /** Should we try to grab the clipboard on startup? */ + bool fGrabClipboardOnStart; + /** The best text format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtText; + /** The best bitmap format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtBmp; + /** The best HTML format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtHTML; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** The best HTML format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtURI; +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP + /** HTTP transfer context data. */ + SHCLHTTPCONTEXT HttpCtx; +# endif +#endif + /** What kind of formats does VBox have to offer? */ + SHCLFORMATS vboxFormats; + /** Cache of the last unicode data that we received. */ + void *pvUnicodeCache; + /** Size of the unicode data in the cache. */ + uint32_t cbUnicodeCache; + /** When we wish the clipboard to exit, we have to wake up the event + * loop. We do this by writing into a pipe. This end of the pipe is + * the end that another thread can write to. */ + int wakeupPipeWrite; + /** The reader end of the pipe. */ + int wakeupPipeRead; + /** A pointer to the XFixesSelectSelectionInput function. */ + void (*fixesSelectInput)(Display *, Window, Atom, unsigned long); + /** The first XFixes event number. */ + int fixesEventBase; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_XT_BUSY + /** XtGetSelectionValue on some versions of libXt isn't re-entrant + * so block overlapping requests on this flag. */ + bool fXtBusy; + /** If a request is blocked on the previous flag, set this flag to request + * an update later - the first callback should check and clear this flag + * before processing the callback event. */ + bool fXtNeedsUpdate; +#endif +} SHCLX11CTX, *PSHCLX11CTX; + +/** + * Structure for keeping a X11 read data request. + */ +typedef struct _SHCLX11READDATAREQ +{ + /** Actual read request to handle. */ + CLIPREADCBREQ *pReq; + /** Result code of the operation on completion. */ + int rcCompletion; +} SHCLX11READDATAREQ; +/** Pointer to a send data request. */ +typedef SHCLX11READDATAREQ *PSHCLX11READDATAREQ; + +/** @name Shared Clipboard APIs for X11. + * @{ + */ +int ShClX11Init(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks, PSHCLCONTEXT pParent, bool fHeadless); +void ShClX11Destroy(PSHCLX11CTX pCtx); +int ShClX11ThreadStart(PSHCLX11CTX pCtx, bool grab); +int ShClX11ThreadStartEx(PSHCLX11CTX pCtx, const char *pszName, bool fGrab); +int ShClX11ThreadStop(PSHCLX11CTX pCtx); +int ShClX11ReportFormatsToX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormats); +int ShClX11ReadDataFromX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormat, CLIPREADCBREQ *pReq); +void ShClX11SetCallbacks(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks); +/** @} */ + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h */ + diff --git a/include/VBox/GuestHost/SharedClipboard.h b/include/VBox/GuestHost/SharedClipboard.h new file mode 100644 index 00000000..e0ad9776 --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard.h @@ -0,0 +1,354 @@ +/** @file + * Shared Clipboard - Common guest and host Code. + */ + +/* + * 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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/critsect.h> +#include <iprt/types.h> +#include <iprt/list.h> + +/** @name VBOX_SHCL_FMT_XXX - Data formats (flags) for Shared Clipboard. + * @{ + */ +/** No format set. */ +#define VBOX_SHCL_FMT_NONE 0 +/** Shared Clipboard format is an Unicode text. */ +#define VBOX_SHCL_FMT_UNICODETEXT RT_BIT(0) +/** Shared Clipboard format is bitmap (BMP / DIB). */ +#define VBOX_SHCL_FMT_BITMAP RT_BIT(1) +/** Shared Clipboard format is HTML. */ +#define VBOX_SHCL_FMT_HTML RT_BIT(2) +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** Shared Clipboard format is a transfer list. */ +# define VBOX_SHCL_FMT_URI_LIST RT_BIT(3) +#endif +/** @} */ + + +/** A single Shared Clipboard format (VBOX_SHCL_FMT_XXX). */ +typedef uint32_t SHCLFORMAT; +/** Pointer to a single Shared Clipboard format (VBOX_SHCL_FMT_XXX). */ +typedef SHCLFORMAT *PSHCLFORMAT; + +/** Bit map (flags) of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */ +typedef uint32_t SHCLFORMATS; +/** Pointer to a bit map of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */ +typedef SHCLFORMATS *PSHCLFORMATS; + + +/** + * Shared Clipboard transfer direction. + */ +typedef enum SHCLTRANSFERDIR +{ + /** Unknown transfer directory. */ + SHCLTRANSFERDIR_UNKNOWN = 0, + /** Read transfer (from source). */ + SHCLTRANSFERDIR_FROM_REMOTE, + /** Write transfer (to target). */ + SHCLTRANSFERDIR_TO_REMOTE, + /** The usual 32-bit hack. */ + SHCLTRANSFERDIR_32BIT_HACK = 0x7fffffff +} SHCLTRANSFERDIR; +/** Pointer to a shared clipboard transfer direction. */ +typedef SHCLTRANSFERDIR *PSHCLTRANSFERDIR; + + +/** + * Shared Clipboard data read request. + */ +typedef struct SHCLDATAREQ +{ + /** In which format the data needs to be sent. */ + SHCLFORMAT uFmt; + /** Read flags; currently unused. */ + uint32_t fFlags; + /** Maximum data (in byte) can be sent. */ + uint32_t cbSize; +} SHCLDATAREQ; +/** Pointer to a shared clipboard data request. */ +typedef SHCLDATAREQ *PSHCLDATAREQ; + +/** + * Shared Clipboard event payload (optional). + */ +typedef struct SHCLEVENTPAYLOAD +{ + /** Payload ID; currently unused. */ + uint32_t uID; + /** Size (in bytes) of actual payload data. */ + uint32_t cbData; + /** Pointer to actual payload data. */ + void *pvData; +} SHCLEVENTPAYLOAD; +/** Pointer to a shared clipboard event payload. */ +typedef SHCLEVENTPAYLOAD *PSHCLEVENTPAYLOAD; + +/** A shared clipboard event source ID. */ +typedef uint16_t SHCLEVENTSOURCEID; +/** Pointer to a shared clipboard event source ID. */ +typedef SHCLEVENTSOURCEID *PSHCLEVENTSOURCEID; + +/** A shared clipboard session ID. */ +typedef uint16_t SHCLSESSIONID; +/** Pointer to a shared clipboard session ID. */ +typedef SHCLSESSIONID *PSHCLSESSIONID; +/** NIL shared clipboard session ID. */ +#define NIL_SHCLSESSIONID UINT16_MAX + +/** A shared clipboard transfer ID. */ +typedef uint16_t SHCLTRANSFERID; +/** Pointer to a shared clipboard transfer ID. */ +typedef SHCLTRANSFERID *PSHCLTRANSFERID; +/** NIL shared clipboardtransfer ID. */ +#define NIL_SHCLTRANSFERID UINT16_MAX + +/** A shared clipboard event ID. */ +typedef uint32_t SHCLEVENTID; +/** Pointer to a shared clipboard event source ID. */ +typedef SHCLEVENTID *PSHCLEVENTID; +/** NIL shared clipboard event ID. */ +#define NIL_SHCLEVENTID UINT32_MAX + +/** Pointer to a shared clipboard event source. + * Forward declaration, needed for SHCLEVENT. */ +typedef struct SHCLEVENTSOURCE *PSHCLEVENTSOURCE; + +/** + * Shared Clipboard event. + */ +typedef struct SHCLEVENT +{ + /** List node. */ + RTLISTNODE Node; + /** Parent (source) this event belongs to. */ + PSHCLEVENTSOURCE pParent; + /** The event's ID, for self-reference. */ + SHCLEVENTID idEvent; + /** Reference count to this event. */ + uint32_t cRefs; + /** Event semaphore for signalling the event. */ + RTSEMEVENTMULTI hEvtMulSem; + /** Payload to this event, optional (NULL). */ + PSHCLEVENTPAYLOAD pPayload; +} SHCLEVENT; +/** Pointer to a shared clipboard event. */ +typedef SHCLEVENT *PSHCLEVENT; + +/** + * Shared Clipboard event source. + * + * Each event source maintains an own counter for events, so that it can be used + * in different contexts. + */ +typedef struct SHCLEVENTSOURCE +{ + /** The event source ID. */ + SHCLEVENTSOURCEID uID; + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** Next upcoming event ID. */ + SHCLEVENTID idNextEvent; + /** List of events (PSHCLEVENT). */ + RTLISTANCHOR lstEvents; +} SHCLEVENTSOURCE; + +/** @name Shared Clipboard data payload functions. + * @{ + */ +int ShClPayloadAlloc(uint32_t uID, const void *pvData, uint32_t cbData, PSHCLEVENTPAYLOAD *ppPayload); +void ShClPayloadFree(PSHCLEVENTPAYLOAD pPayload); +/** @} */ + +/** @name Shared Clipboard event source functions. + * @{ + */ +int ShClEventSourceCreate(PSHCLEVENTSOURCE pSource, SHCLEVENTSOURCEID idEvtSrc); +int ShClEventSourceDestroy(PSHCLEVENTSOURCE pSource); +void ShClEventSourceReset(PSHCLEVENTSOURCE pSource); +int ShClEventSourceGenerateAndRegisterEvent(PSHCLEVENTSOURCE pSource, PSHCLEVENT *ppEvent); +PSHCLEVENT ShClEventSourceGetFromId(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent); +PSHCLEVENT ShClEventSourceGetLast(PSHCLEVENTSOURCE pSource); +/** @} */ + +/** @name Shared Clipboard event functions. + * @{ + */ +uint32_t ShClEventGetRefs(PSHCLEVENT pEvent); +uint32_t ShClEventRetain(PSHCLEVENT pEvent); +uint32_t ShClEventRelease(PSHCLEVENT pEvent); +int ShClEventSignal(PSHCLEVENT pEvent, PSHCLEVENTPAYLOAD pPayload); +int ShClEventWait(PSHCLEVENT pEvent, RTMSINTERVAL uTimeoutMs, PSHCLEVENTPAYLOAD *ppPayload); +/** @} */ + +/** + * Shared Clipboard transfer source type. + * @note Part of saved state! + */ +typedef enum SHCLSOURCE +{ + /** Invalid source type. */ + SHCLSOURCE_INVALID = 0, + /** Source is local. */ + SHCLSOURCE_LOCAL, + /** Source is remote. */ + SHCLSOURCE_REMOTE, + /** The usual 32-bit hack. */ + SHCLSOURCE_32BIT_HACK = 0x7fffffff +} SHCLSOURCE; + +/** Opaque data structure for the X11/VBox frontend/glue code. + * @{ */ +struct SHCLCONTEXT; +typedef struct SHCLCONTEXT SHCLCONTEXT; +/** @} */ +/** Pointer to opaque data structure the X11/VBox frontend/glue code. */ +typedef SHCLCONTEXT *PSHCLCONTEXT; + +/** + * @name Shared Clipboard callback table. + * + * This table gets used by + * - the backends on the host (where required) + * - guest side implementations (e.g. VBoxClient) + * - by the underlying core code (e.g. X11 backend -> X11 common code -> callback) + * + * Some clipboard mechanisms (e.g. X11) require asynchronous and/or event-driven handling + * of clipboard data, making it hard to control our program flow when testing stuff. + * + * So overriding required callbacks on runtime for testing purposes makes this approach much + * more flexible without implementing separate code paths for production code and test units. + * + * @{ + */ +typedef struct _SHCLCALLBACKS +{ + /** + * Callback for reporting supported clipoard formats of current clipboard data. + * + * @note On X11: + * Runs in Xt event thread for the X11 code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param fFormats The formats available. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnReportFormats, (PSHCLCONTEXT pCtx, SHCLFORMATS fFormats, void *pvUser)); + + /** + * Callback for reading data from the clipboard. + * Optional and can be NULL. + * + * @note Used for testing X11 clipboard code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be read + * (VBOX_SHCL_FMT_XXX). + * @param ppv Returns an allocated buffer with data from on success. + * Needs to be free'd with RTMemFree() by the caller. + * @param pcb Returns the amount of data read (in bytes) on success. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnOnClipboardRead, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, size_t *pcb, void *pvUser)); + + /** + * Callback for writing data to the clipboard. + * Optional and can be NULL. + * + * @note Used for testing X11 clipboard code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be written as + * (VBOX_SHCL_FMT_XXX). + * @param pv The clipboard data to write. + * @param cb The size of the data in @a pv. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnOnClipboardWrite, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void *pv, size_t cb, void *pvUser)); + + /** + * Callback for requesting clipboard data from the source. + * + * @note On X11: + * The function will be invoked for every single target the clipboard requests. + * Runs in Xt event thread for the X11 code. + * + * @returns VBox status code. VERR_NO_DATA if no data available. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be transferred + * (VBOX_SHCL_FMT_XXX). + * @param ppv Returns an allocated buffer with data read from the guest on success. + * Needs to be free'd with RTMemFree() by the caller. + * @param pcb Returns the amount of data read (in bytes) on success. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + * On X11: Of type PSHCLX11READDATAREQ; We RTMemFree() this in this function. + */ + DECLCALLBACKMEMBER(int, pfnOnRequestDataFromSource, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)); + + /** + * Callback for sending clipboard data to the destination. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param pv The clipboard data returned if the request succeeded. + * @param cb The size of the data in @a pv. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NUL + * On X11: Of type PSHCLX11READDATAREQ. + */ + DECLCALLBACKMEMBER(int, pfnOnSendDataToDest, (PSHCLCONTEXT pCtx, void *pv, uint32_t cb, void *pvUser)); +} SHCLCALLBACKS; +typedef SHCLCALLBACKS *PSHCLCALLBACKS; +/** @} */ + +/** Opaque request structure for X11 clipboard data. + * @{ */ +struct CLIPREADCBREQ; +typedef struct CLIPREADCBREQ CLIPREADCBREQ; +/** @} */ + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_h */ + diff --git a/include/VBox/GuestHost/clipboard-helper.h b/include/VBox/GuestHost/clipboard-helper.h new file mode 100644 index 00000000..97600993 --- /dev/null +++ b/include/VBox/GuestHost/clipboard-helper.h @@ -0,0 +1,250 @@ +/* $Id: clipboard-helper.h $ */ +/** @file + * Shared Clipboard - Some helper function for converting between the various EOLs. + */ + +/* + * 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>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_clipboard_helper_h +#define VBOX_INCLUDED_GuestHost_clipboard_helper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <iprt/string.h> + +#include <VBox/GuestHost/SharedClipboard.h> + +/** Constants needed for string conversions done by the Linux/Mac clipboard code. */ +enum +{ + /** In Linux, lines end with a linefeed character. */ + VBOX_SHCL_LINEFEED = 0xa, + /** In Windows, lines end with a carriage return and a linefeed character. */ + VBOX_SHCL_CARRIAGERETURN = 0xd, + /** Little endian "real" UTF-16 strings start with this marker. */ + VBOX_SHCL_UTF16LEMARKER = 0xfeff, + /** Big endian "real" UTF-16 strings start with this marker. */ + VBOX_SHCL_UTF16BEMARKER = 0xfffe +}; + +/** + * Returns the length (in UTF-8 characters) of an UTF-16 string with LF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16LFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Returns the length (in UTF-8 characters) of an UTF-16 string with CRLF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the source string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16CRLFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Returns the length (in characters) of an UTF-16 string, including terminator. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the source string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16LenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Converts an UTF-16 string with LF EOL to an UTF-16 string with CRLF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string int RTUTF16 units. + * @param pwszDst Buffer to store the converted string to. + * @param cwcDst The size of \a pwszDst in RTUTF16 units. + */ +int ShClConvUtf16LFToCRLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pwszDst, size_t cwcDst); + +/** + * Converts an UTF-16 string with LF EOL to an UTF-16 string with CRLF EOL. + * + * Convenience function which returns the allocated + converted string on success. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string int RTUTF16 units. + * @param ppwszDst Where to return the allocated converted string. Must be free'd by the caller. + * @param pcwDst Where to return the size of the converted string in RTUTF16 units. + * Does not include the terminator. + */ +int ShClConvUtf16LFToCRLFA(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Converts an UTF-16 string with CRLF EOL to an UTF-16 string with LF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string in RTUTF16 units. + * @param pwszDst Where to store the converted string to. + * @param cwcDst The size of \a pwszDst in RTUTF16 units. + */ +int ShClConvUtf16CRLFToLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pwszDst, size_t cwcDst); + +/** + * Converts an UTF-16 string with CRLF EOL to UTF-8 LF. + * + * @returns VBox status code. Will return VERR_NO_DATA if no data was converted. + * @param pcwszSrc UTF-16 string to convert. + * @param cbSrc Length of @a pwszSrc (in bytes). + * @param pszBuf Where to write the converted string. + * @param cbBuf The size of the buffer pointed to by @a pszBuf. + * @param pcbLen Where to store the size (in bytes) of the converted string. + * Does not include terminator. + */ +int ShClConvUtf16CRLFToUtf8LF(PCRTUTF16 pcwszSrc, size_t cbSrc, char *pszBuf, size_t cbBuf, size_t *pcbLen); + +/** +* Converts an HTML string from UTF-16 into UTF-8. +* +* @returns VBox status code. +* @param pcwszSrc UTF-16 string to convert. +* @param cwcSrc Length (in RTUTF16 units) of the source text. +* @param ppszDst Where to store the converted result on success. +* @param pcbDst Where to store the number of bytes written. +*/ +int ShClConvUtf16ToUtf8HTML(PCRTUTF16 pcwszSrc, size_t cwcSrc, char **ppszDst, size_t *pcbDst); + +/** + * Converts an UTF-8 string with LF EOL into UTF-16 CRLF. + * + * @returns VBox status code. + * @param pcszSrc UTF-8 string to convert. + * @param cbSrc Size of UTF-8 string to convert (in bytes), not counting the terminating zero. + * @param ppwszDst Where to return the allocated buffer on success. + * @param pcwDst Where to return the size (in RTUTF16 units) of the allocated buffer on success. + * Does not include terminator. + */ +int ShClConvUtf8LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Converts a Latin-1 string with LF EOL into UTF-16 CRLF. + * + * @returns VBox status code. + * @param pcszSrc UTF-8 string to convert. + * @param cbSrc Size of string (in bytes), not counting the terminating zero. + * @param ppwszDst Where to return the allocated buffer on success. + * @param pcwDst Where to return the size (in RTUTF16 units) of the allocated buffer on success. + * Does not include terminator. + */ +int ShClConvLatin1LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Convert CF_DIB data to full BMP data by prepending the BM header. + * Allocates with RTMemAlloc. + * + * @returns VBox status code. + * @param pvSrc DIB data to convert + * @param cbSrc Size of the DIB data to convert in bytes + * @param ppvDst Where to store the pointer to the buffer for the + * destination data + * @param pcbDst Pointer to the size of the buffer for the destination + * data in bytes. + */ +int ShClDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDst, size_t *pcbDst); + +/** + * Get the address and size of CF_DIB data in a full BMP data in the input buffer. + * Does not do any allocation. + * + * @returns VBox status code. + * @param pvSrc BMP data to convert + * @param cbSrc Size of the BMP data to convert in bytes + * @param ppvDst Where to store the pointer to the destination data + * @param pcbDst Pointer to the size of the destination data in bytes + */ +int ShClBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDst, size_t *pcbDst); + +#ifdef LOG_ENABLED +/** + * Dumps HTML data to the debug log. + * + * @returns VBox status code. + * @param pszSrc HTML data to dump. + * @param cbSrc Size (in bytes) of HTML data to dump. + */ +int ShClDbgDumpHtml(const char *pszSrc, size_t cbSrc); + +/** + * Dumps data using a specified clipboard format. + * + * @param pv Pointer to data to dump. + * @param cb Size (in bytes) of data to dump. + * @param u32Format Clipboard format to use for dumping. + */ +void ShClDbgDumpData(const void *pv, size_t cb, SHCLFORMAT u32Format); +#endif /* LOG_ENABLED */ + +/** + * Translates a Shared Clipboard host function number to a string. + * + * @returns Function ID string name. + * @param uFn The function to translate. + */ +const char *ShClHostFunctionToStr(uint32_t uFn); + +/** + * Translates a Shared Clipboard host message enum to a string. + * + * @returns Message ID string name. + * @param uMsg The message to translate. + */ +const char *ShClHostMsgToStr(uint32_t uMsg); + +/** + * Translates a Shared Clipboard guest message enum to a string. + * + * @returns Message ID string name. + * @param uMsg The message to translate. + */ +const char *ShClGuestMsgToStr(uint32_t uMsg); + +char *ShClFormatsToStrA(SHCLFORMATS fFormats); + +#endif /* !VBOX_INCLUDED_GuestHost_clipboard_helper_h */ + |