service.cpp revision 2673f120424ba2bb67c6da0eb851b65b22b0cba4
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Guest Property Service:
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Host service entry points.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * available from http://www.virtualbox.org. This file is free software;
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * you can redistribute it and/or modify it under the terms of the GNU
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * General Public License (GPL) as published by the Free Software
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * additional information or have any questions.
0d12c7f9423f2745f8e282523d0930f91bff03b3vboxsync * This HGCM service allows the guest to set and query values in a property
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * store on the host. The service proxies the guest requests to the service
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * owner on the host using a request callback provided by the owner, and is
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * notified of changes to properties made by the host. It forwards these
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * notifications to clients in the guest which have expressed interest and
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * are waiting for notification.
032a52c5b2984e26e84c2961f8f7f98a3954c8f2vboxsync * The service currently consists of two threads. One of these is the main
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * HGCM service thread which deals with requests from the guest and from the
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync * host. The second thread sends the host asynchronous notifications of
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * changes made by the guest and deals with notification timeouts.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Guest requests to wait for notification are added to a list of open
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * notification requests and completed when a corresponding guest property
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * is changed or when the request times out.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync/*******************************************************************************
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync* Header Files *
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync*******************************************************************************/
044af0d1e6474076366759db86f101778c5f20ccvboxsync/*******************************************************************************
044af0d1e6474076366759db86f101778c5f20ccvboxsync* Internal functions *
044af0d1e6474076366759db86f101778c5f20ccvboxsync*******************************************************************************/
044af0d1e6474076366759db86f101778c5f20ccvboxsync/** Extract a pointer value from an HGCM parameter structure */
044af0d1e6474076366759db86f101778c5f20ccvboxsyncstatic int VBoxHGCMParmPtrGet (VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb)
044af0d1e6474076366759db86f101778c5f20ccvboxsync/** Set a uint32_t value to an HGCM parameter structure */
044af0d1e6474076366759db86f101778c5f20ccvboxsyncstatic void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32)
044af0d1e6474076366759db86f101778c5f20ccvboxsync/** Set a uint64_t value to an HGCM parameter structure */
044af0d1e6474076366759db86f101778c5f20ccvboxsyncstatic void VBoxHGCMParmUInt64Set (VBOXHGCMSVCPARM *pParm, uint64_t u64)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Class containing the shared information service functionality.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync /** Type definition for use in callback functions */
044af0d1e6474076366759db86f101778c5f20ccvboxsync /** HGCM helper functions. */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync /** Pointer to our configuration values node. */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync /** Pointer to our configuration timestamps node. */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Pointer to our configuration flags node. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync /** @todo we should have classes for thread and request handler thread */
044af0d1e6474076366759db86f101778c5f20ccvboxsync /** Queue of outstanding property change notifications */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Thread for processing the request queue */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Tell the thread that it should exit */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** Callback function supplied by the host for notification of updates
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * to properties */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /** User data pointer to be supplied to the host callback function */
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync : mpHelpers(pHelpers), mpValueNode(NULL), mpTimestampNode(NULL),
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync mpFlagsNode(NULL), mfExitThread(false), mpfnHostCallback(NULL),
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, RTTHREADTYPE_MSG_PUMP,
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnUnload
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync * Simply deletes the service object
a1df400bbe9d64aad400442e56eb637019300a5evboxsync static DECLCALLBACK(int) svcUnload (void *pvService)
a1df400bbe9d64aad400442e56eb637019300a5evboxsync AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * Stub implementation of pfnConnect and pfnDisconnect.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync static DECLCALLBACK(int) svcConnectDisconnect (void * /* pvService */,
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync void * /* pvClient */)
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnCall
044af0d1e6474076366759db86f101778c5f20ccvboxsync * Wraps to the call member function
044af0d1e6474076366759db86f101778c5f20ccvboxsync static DECLCALLBACK(void) svcCall (void * pvService,
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnHostCall
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync * Wraps to the hostCall member function
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync static DECLCALLBACK(int) svcHostCall (void *pvService,
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync return pSelf->hostCall(u32Function, cParms, paParms);
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnRegisterExtension
7d80dfbe5d66fc4c6de6fe109ce96a081496dcd4vboxsync * Installs a host callback for notifications of property changes.
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync static DECLCALLBACK(int) svcRegisterExtension (void *pvService,
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int validateName(const char *pszName, uint32_t cbName);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int validateValue(char *pszValue, uint32_t cbValue);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync static DECLCALLBACK(int) reqNotify(PFNHGCMSVCEXT pfnCallback,
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Empty request function for terminating the request thread.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @returns VINF_EOF to cause the request processing function to return
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @todo return something more appropriate
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync static DECLCALLBACK(int) reqVoid() { return VINF_EOF; }
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync void call (VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync void *pvClient, uint32_t eFunction, uint32_t cParms,
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync int hostCall (uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Thread function for processing the request queue
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @copydoc FNRTTHREAD
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncDECLCALLBACK(int) Service::reqThreadFn(RTTHREAD ThreadSelf, void *pvUser)
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync RTReqProcess(pSelf->mReqQueue, RT_INDEFINITE_WAIT);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * Checking that the name passed by the guest fits our criteria for a
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * property name.
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * @returns IPRT status code
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * @param pszName the name passed by the guest
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * @param cbName the number of bytes pszName points to, including the
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * terminating '\0'
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @thread HGCM
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncint Service::validateName(const char *pszName, uint32_t cbName)
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * Validate the name, checking that it's proper UTF-8 and has
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * a string terminator.
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync int rc = RTStrValidateEncodingEx(pszName, RT_MIN(cbName, (uint32_t) MAX_NAME_LEN),
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Check that the data passed by the guest fits our criteria for the value of
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * a guest property.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @returns IPRT status code
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @param pszValue the value to store in the property
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @param cbValue the number of bytes in the buffer pszValue points to
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @thread HGCM
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncint Service::validateValue(char *pszValue, uint32_t cbValue)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Validate the value, checking that it's proper UTF-8 and has
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * a string terminator. Don't pass a 0 length request to the
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * validator since it won't find any '\0' then.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = RTStrValidateEncodingEx(pszValue, RT_MIN(cbValue, (uint32_t) MAX_VALUE_LEN),
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync LogFlow((" pszValue=%s\n", cbValue > 0 ? pszValue : NULL));
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Retrieve a value from the property registry by name, checking the validity
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * of the arguments passed. If the guest has not allocated enough buffer
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * space for the value then we return VERR_OVERFLOW and set the size of the
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * buffer needed in the "size" HGCM parameter. If the name was not found at
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * all, we return VERR_NOT_FOUND.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @returns iprt status value
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * @param cParms the number of HGCM parameters supplied
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * @param paParms the array of HGCM parameters
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @thread HGCM
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncint Service::getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* value */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cbValue);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = CFGMR3QuerySize(mpValueNode, pszName, &cbValueActual);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = CFGMR3QueryString(mpValueNode, pszName, pszValue, cbValue);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Log2(("Queried string %s, rc=%Rrc, value=%.*s\n", pszName, rc, cbValue, pszValue));
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Retrieve a value from the property registry by name, checking the validity
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * of the arguments passed. If the guest has not allocated enough buffer
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * space for the value then we return VERR_OVERFLOW and set the size of the
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * buffer needed in the "size" HGCM parameter. If the name was not found at
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * all, we return VERR_NOT_FOUND.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @returns iprt status value
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * @param cParms the number of HGCM parameters supplied
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @param paParms the array of HGCM parameters
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @thread HGCM
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncint Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Get and validate the parameters
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync if ( (cParms != 4) /* Hardcoded value as the next lines depend on it. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* buffer */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Read and set the values we will return
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Get the value size */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = CFGMR3QuerySize(mpValueNode, pszName, &cchValue);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Get the flags and their size */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync CFGMR3QueryU32(mpFlagsNode, pszName, (uint32_t *)&fFlags);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Check that the buffer is big enough */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Write the value */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = CFGMR3QueryString(mpValueNode, pszName, pchBuf, cchBuf);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Write the flags */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Timestamp */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync CFGMR3QueryU64(mpTimestampNode, pszName, &u64Timestamp);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Done! Do exit logging and return.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Log2(("Queried string %S, value=%.*S, timestamp=%lld, flags=%.*S\n",
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync * Set a value in the property registry by name, checking the validity
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync * of the arguments passed.
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync * @returns iprt status value
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync * @param cParms the number of HGCM parameters supplied
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync * @param paParms the array of HGCM parameters
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync * @thread HGCM
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsyncint Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync * First of all, make sure that we won't exceed the maximum number of properties.
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync unsigned cChildren = 0;
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync for (PCFGMNODE pChild = CFGMR3GetFirstChild(mpValueNode); pChild != 0; pChild = CFGMR3GetNextChild(pChild))
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync * General parameter correctness checking.
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync && ( (cParms < 2) || (cParms > 4) /* Hardcoded value as the next lines depend on it. */
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* value */
9b19ad593b379ebfcc8273f85b90763b14b1da63vboxsync || ((3 == cParms) && (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR)) /* flags */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Check the values passed in the parameters for correctness.
ca3da10d05961c339b5180fbd40a54587d6bad35vboxsync rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue);
044af0d1e6474076366759db86f101778c5f20ccvboxsync * If the property already exists, check its flags to see if we are allowed
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * to change it.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags); /* Failure is no problem here. */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Check whether the user supplied flags (if any) are valid.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = VBoxHGCMParmPtrGet(&paParms[2], (void **) &pszFlags, &cchFlags);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Set the actual value
9d020a0622f95aec3aabaff436a495e88dbbd71avboxsync rc = CFGMR3InsertString(mpValueNode, pszName, pszValue);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync rc = CFGMR3InsertInteger(mpFlagsNode, pszName, fFlags);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* If anything goes wrong, make sure that we leave a clean state
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * behind. */
9d020a0622f95aec3aabaff436a495e88dbbd71avboxsync * Send a notification to the host and return.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync Log2(("Set string %s, rc=%Rrc, value=%s\n", pszName, rc, pszValue));
9d020a0622f95aec3aabaff436a495e88dbbd71avboxsync * Remove a value in the property registry by name, checking the validity
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * of the arguments passed.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @returns iprt status value
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @param cParms the number of HGCM parameters supplied
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @param paParms the array of HGCM parameters
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @thread HGCM
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncint Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Check the user-supplied parameters.
044af0d1e6474076366759db86f101778c5f20ccvboxsync if ( (cParms != 1) /* Hardcoded value as the next lines depend on it. */
044af0d1e6474076366759db86f101778c5f20ccvboxsync || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* name */
044af0d1e6474076366759db86f101778c5f20ccvboxsync rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName);
044af0d1e6474076366759db86f101778c5f20ccvboxsync * If the property already exists, check its flags to see if we are allowed
044af0d1e6474076366759db86f101778c5f20ccvboxsync * to change it.
044af0d1e6474076366759db86f101778c5f20ccvboxsync CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags); /* Failure is no problem here. */
5eda82e218d35ae0691febd531e1bfc0324cc4a6vboxsync * And delete the property if all is well.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * Enumerate guest properties by mask, checking the validity
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * of the arguments passed.
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @returns iprt status value
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @param cParms the number of HGCM parameters supplied
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @param paParms the array of HGCM parameters
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * @thread HGCM
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsyncint Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* We reallocate the temporary buffer in which we build up our array in
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * increments of size BLOCK: */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /* Calculate the increment, not yet rounded down */
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync BLOCKINCRFULL = (MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 2048),
3a4a6501d0ccd629d9951b644d380c7bb2d46086vboxsync /* And this is the increment after rounding */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * Get the HGCM function arguments.
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER); /* a.k.a. VERR_NOT_INITIALIZED */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if ( (cParms != 3) /* Hardcoded value as the next lines depend on it. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* patterns */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* return buffer */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &paszPatterns, &cchPatterns);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if (RT_SUCCESS(rc) && cchPatterns > MAX_PATTERN_LEN)
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf);
9939c713bffcfc4305d99d994552aa2ad9bce097vboxsync * First repack the patterns into the format expected by RTStrSimplePatternMatch()
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync bool matchAll = false;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync || (cchPatterns < 2) /* An empty pattern string means match all */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * Next enumerate all values in the current node into a temporary buffer.
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync PCFGMLEAF pLeaf = CFGMR3GetFirstValue(mpValueNode);
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Reallocate the buffer if it has got too tight */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Fetch the name into the buffer and if it matches one of the
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * patterns, add its value and an empty timestamp and flags. If it
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * doesn't match, we simply overwrite it in the buffer. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = CFGMR3GetValueName(pLeaf, &TmpBuf[iTmpBuf], cchTmpBuf - iTmpBuf);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Only increment the buffer offest if the name matches, otherwise we
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * overwrite it next iteration. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX,
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Get value */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync rc = CFGMR3QueryString(mpValueNode, pszName, &TmpBuf[iTmpBuf],
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync /* Get timestamp */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync CFGMR3QueryU64(mpTimestampNode, pszName, &u64Timestamp);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync iTmpBuf += RTStrFormatNumber(&TmpBuf[iTmpBuf], u64Timestamp,
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync /* Get flags */
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync TmpBuf[iTmpBuf] = '\0'; /* Bad (== in)sanity, will be fixed. */
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync /* The terminator. We *do* have space left for this. */
bbb4c0bfd5ea55e99591d8811771257a437053eevboxsync /* Copy the memory if it fits into the guest buffer */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * Notify the service owner that a property has been added/deleted/changed
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * @param pszProperty the name of the property which has changed
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * @note this call allocates memory which the reqNotify request is expected to
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * free again, using RTStrFree().
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * @thread HGCM service
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL;
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync return; /* Nothing to do. */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync int rc = CFGMR3QueryString(mpValueNode, pszProperty, szValue,
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * First case: if the property exists then send the host its current value
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = CFGMR3QueryU64(mpTimestampNode, pszProperty, &u64Timestamp);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = CFGMR3QueryU32(mpFlagsNode, pszProperty, &fFlags);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT,
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * Second case: if the property does not exist then send the host an empty
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT,
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync if (RT_FAILURE(rc)) /* clean up if we failed somewhere */
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * Notify the service owner that a property has been added/deleted/changed.
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * asynchronous part.
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * @param pszProperty the name of the property which has changed
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * @note this call allocates memory which the reqNotify request is expected to
4a1654dd5b9f0ae4e149d909843a3ab07b8bec33vboxsync * free again, using RTStrFree().
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync * @thread request thread
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsyncint Service::reqNotify(PFNHGCMSVCEXT pfnCallback, void *pvData,
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync char *pszName, char *pszValue, uint32_t u32TimeHigh,
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync HostCallbackData.u64Timestamp = RT_MAKE_U64(u32TimeLow, u32TimeHigh);
c0e27f622f9bd6d9e77d2d959aab71d69dabf0d3vboxsync AssertRC(pfnCallback(pvData, 0, reinterpret_cast<void *>(&HostCallbackData),
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * Handle an HGCM service call.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @note All functions which do not involve an unreasonable delay will be
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * handled synchronously. If needed, we will add a request handler
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * thread in future for those which do.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @thread HGCM
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncvoid Service::call (VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync void * /* pvClient */, uint32_t eFunction, uint32_t cParms,
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The guest wishes to read a property */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The guest wishes to set a property */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The guest wishes to set a property value */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The guest wishes to remove a configuration value */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The guest wishes to enumerate all properties */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * Service call handler for the host.
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @thread hgcm
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncint Service::hostCall (uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync LogFlowFunc(("fn = %d, cParms = %d, pparms = %d\n",
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* Set the root CFGM node used. This should be called when instantiating
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * the service. */
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync /* This whole case is due to go away, so I will not clean it up. */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR) /* pValue */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR) /* pTimestamp */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync || (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR) /* pFlags */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync PCFGMNODE pValue = NULL, pTimestamp = NULL, pFlags = NULL;
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc = VBoxHGCMParmPtrGet (&paParms[0], (void **) &pValue, &cbDummy);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc = VBoxHGCMParmPtrGet (&paParms[1], (void **) &pTimestamp, &cbDummy);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc = VBoxHGCMParmPtrGet (&paParms[2], (void **) &pFlags, &cbDummy);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The host wishes to read a configuration value */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The host wishes to set a configuration value */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The host wishes to set a configuration value */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The host wishes to remove a configuration value */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* The host wishes to enumerate all properties */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync unsigned count = 0;
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, (PFNRT)reqVoid, 0);
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync} /* namespace guestProp */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync * @copydoc VBOXHGCMSVCLOAD
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsyncextern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* No exceptions may propogate outside. */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync } catch (int rcThrown) {
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync } catch (...) {
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* We do not maintain connections, so no client data is needed. */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync ptable->pfnConnect = Service::svcConnectDisconnect;
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync ptable->pfnDisconnect = Service::svcConnectDisconnect;
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync ptable->pfnSaveState = NULL; /* The service is stateless by definition, so the */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync ptable->pfnLoadState = NULL; /* normal construction done before restoring suffices */
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync ptable->pfnRegisterExtension = Service::svcRegisterExtension;
df8e6a449f00e1884fbf4a1fc67143614d7d528dvboxsync /* Service specific initialization. */