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