VirtualBox

Changeset 13759 in vbox


Ignore:
Timestamp:
Nov 3, 2008 4:13:04 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
38734
Message:

Guest Properties (HostServices and Main): major clean up of the guest property service

Location:
trunk
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/HostServices/GuestPropertySvc.h

    r13574 r13759  
    148148                break;
    149149        if (RT_ELEMENTS(flagList) == i)
    150              rc = VERR_INVALID_PARAMETER;
     150             rc = VERR_PARSE_ERROR;
    151151        else
    152152        {
     
    157157            if (',' == *pcszNext)
    158158                ++pcszNext;
     159            else if (*pcszNext != '\0')
     160                rc = VERR_PARSE_ERROR;
    159161            while (' ' == *pcszNext)
    160162                ++pcszNext;
     
    189191        for (; i < RT_ELEMENTS(flagList); ++i)
    190192        {
    191             if (fFlags & flagList[i])
     193            if (flagList[i] == (fFlags & flagList[i]))
    192194            {
    193195                strcpy(pszNext, flagName(flagList[i]));
     
    213215enum eHostFn
    214216{
    215     /** Pass the address of the cfgm node used by the service as a database. */
    216     SET_CFGM_NODE = 1,
     217    /**
     218     * Set properties in a block.  The parameters are pointers to
     219     * NULL-terminated arrays containing the paramters.  These are, in order,
     220     * name, value, timestamp, flags.  Strings are stored as pointers to
     221     * mutable utf8 data.  All parameters must be supplied.
     222     */
     223    SET_PROPS_HOST = 1,
    217224    /**
    218225     * Get the value attached to a guest property
  • trunk/src/VBox/HostServices/GuestProperties/service.cpp

    r13574 r13759  
    4747
    4848#include <memory>  /* for auto_ptr */
     49#include <string>
     50#include <list>
    4951
    5052#include <iprt/err.h>
     
    5961#include <VBox/log.h>
    6062
    61 #include <VBox/cfgm.h>
    62 
    6363/*******************************************************************************
    6464*   Internal functions                                                         *
     
    7777}
    7878
     79/** Extract a constant pointer value from an HGCM parameter structure */
     80static int VBoxHGCMParmPtrConstGet (VBOXHGCMSVCPARM *pParm, const void **ppv, uint32_t *pcb)
     81{
     82    if (pParm->type == VBOX_HGCM_SVC_PARM_PTR)
     83    {
     84        *ppv = pParm->u.pointer.addr;
     85        *pcb = pParm->u.pointer.size;
     86        return VINF_SUCCESS;
     87    }
     88
     89    return VERR_INVALID_PARAMETER;
     90}
     91
    7992/** Set a uint32_t value to an HGCM parameter structure */
    8093static void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32)
     
    8497}
    8598
    86 
    8799/** Set a uint64_t value to an HGCM parameter structure */
    88100static void VBoxHGCMParmUInt64Set (VBOXHGCMSVCPARM *pParm, uint64_t u64)
     
    90102    pParm->type = VBOX_HGCM_SVC_PARM_64BIT;
    91103    pParm->u.uint64 = u64;
     104}
     105
     106/** Set a pointer value to an HGCM parameter structure */
     107static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb)
     108{
     109    pParm->type = VBOX_HGCM_SVC_PARM_PTR;
     110    pParm->u.pointer.addr = pv;
     111    pParm->u.pointer.size = cb;
    92112}
    93113
     
    104124    /** HGCM helper functions. */
    105125    PVBOXHGCMSVCHELPERS mpHelpers;
    106     /** Pointer to our configuration values node. */
    107     PCFGMNODE mpValueNode;
    108     /** Pointer to our configuration timestamps node. */
    109     PCFGMNODE mpTimestampNode;
    110     /** Pointer to our configuration flags node. */
    111     PCFGMNODE mpFlagsNode;
     126    /** Structure for holding a property */
     127    struct Property
     128    {
     129        /** The name of the property */
     130        std::string mName;
     131        /** The property value */
     132        std::string mValue;
     133        /** The timestamp of the property */
     134        uint64_t mTimestamp;
     135        /** The property flags */
     136        uint32_t mFlags;
     137        /** Constructor with const char * */
     138        Property(const char *pcszName, const char *pcszValue,
     139                 uint64_t u64Timestamp, uint32_t u32Flags)
     140            : mName(pcszName), mValue(pcszValue), mTimestamp(u64Timestamp),
     141              mFlags(u32Flags) {}
     142        /** Constructor with std::string */
     143        Property(std::string name, std::string value, uint64_t u64Timestamp,
     144                 uint32_t u32Flags)
     145            : mName(name), mValue(value), mTimestamp(u64Timestamp),
     146              mFlags(u32Flags) {}
     147    };
     148    /** The properties list type */
     149    typedef std::list <Property> PropertyList;
     150    /** The property list */
     151    PropertyList mProperties;
    112152    /** @todo we should have classes for thread and request handler thread */
    113153    /** Queue of outstanding property change notifications */
     
    125165public:
    126166    explicit Service(PVBOXHGCMSVCHELPERS pHelpers)
    127         : mpHelpers(pHelpers), mpValueNode(NULL), mpTimestampNode(NULL),
    128           mpFlagsNode(NULL), mfExitThread(false), mpfnHostCallback(NULL),
     167        : mpHelpers(pHelpers), mfExitThread(false), mpfnHostCallback(NULL),
    129168          mpvHostData(NULL)
    130169    {
    131170        int rc = RTReqCreateQueue(&mReqQueue);
    132         rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0, RTTHREADTYPE_MSG_PUMP,
    133                                 RTTHREADFLAGS_WAITABLE, "GuestPropReq");
     171#ifndef VBOX_GUEST_PROP_TEST_NOTHREAD
     172        if (RT_SUCCESS(rc))
     173            rc = RTThreadCreate(&mReqThread, reqThreadFn, this, 0,
     174                                RTTHREADTYPE_MSG_PUMP, RTTHREADFLAGS_WAITABLE,
     175                                "GuestPropReq");
     176#endif
    134177        if (RT_FAILURE(rc))
    135178            throw rc;
     
    210253    static DECLCALLBACK(int) reqThreadFn(RTTHREAD ThreadSelf, void *pvUser);
    211254    int validateName(const char *pszName, uint32_t cbName);
    212     int validateValue(char *pszValue, uint32_t cbValue);
    213     int getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
     255    int validateValue(const char *pszValue, uint32_t cbValue);
     256    int setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    214257    int getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
    215258    int setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest);
     
    286329 * @thread  HGCM
    287330 */
    288 int Service::validateValue(char *pszValue, uint32_t cbValue)
     331int Service::validateValue(const char *pszValue, uint32_t cbValue)
    289332{
    290333    LogFlowFunc(("cbValue=%d\n", cbValue));
     
    305348}
    306349
     350/**
     351 * Set a block of properties in the property registry, checking the validity
     352 * of the arguments passed.
     353 *
     354 * @returns iprt status value
     355 * @param   cParms  the number of HGCM parameters supplied
     356 * @param   paParms the array of HGCM parameters
     357 * @thread  HGCM
     358 */
     359int Service::setPropertyBlock(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     360{
     361    char **ppNames, **ppValues, **ppFlags;
     362    uint64_t *pTimestamps;
     363    uint32_t cbDummy;
     364    int rc = VINF_SUCCESS;
     365
     366    /*
     367     * Get and validate the parameters
     368     */
     369    if (   (cParms != 4)
     370        || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[0], (void **) &ppNames, &cbDummy))
     371        || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[1], (void **) &ppValues, &cbDummy))
     372        || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[2], (void **) &pTimestamps, &cbDummy))
     373        || RT_FAILURE(VBoxHGCMParmPtrGet (&paParms[3], (void **) &ppFlags, &cbDummy))
     374        )
     375        rc = VERR_INVALID_PARAMETER;
     376
     377    /*
     378     * Add the properties to the end of the list.  If we succeed then we
     379     * will remove duplicates afterwards.
     380     */
     381    /* Remember the last property before we started adding, for rollback or
     382     * cleanup. */
     383    PropertyList::iterator itEnd = mProperties.end();
     384    if (!mProperties.empty())
     385        --itEnd;
     386    try
     387    {
     388        for (unsigned i = 0; RT_SUCCESS(rc) && ppNames[i] != NULL; ++i)
     389        {
     390            uint32_t fFlags;
     391            if (   !VALID_PTR(ppNames[i])
     392                || !VALID_PTR(ppValues[i])
     393                || !VALID_PTR(ppFlags[i])
     394              )
     395                rc = VERR_INVALID_POINTER;
     396            if (RT_SUCCESS(rc))
     397                rc = validateFlags(ppFlags[i], &fFlags);
     398            if (RT_SUCCESS(rc))
     399                mProperties.push_back(Property(ppNames[i], ppValues[i],
     400                                               pTimestamps[i], fFlags));
     401        }
     402    }
     403    catch (std::bad_alloc)
     404    {
     405        rc = VERR_NO_MEMORY;
     406    }
     407
     408    /*
     409     * If all went well then remove the duplicate elements.
     410     */
     411    if (RT_SUCCESS(rc) && itEnd != mProperties.end())
     412    {
     413        ++itEnd;
     414        for (unsigned i = 0; ppNames[i] != NULL; ++i)
     415        {
     416            bool found = false;
     417            for (PropertyList::iterator it = mProperties.begin();
     418                !found && it != itEnd; ++it)
     419                if (it->mName.compare(ppNames[i]) == 0)
     420                {
     421                    found = true;
     422                    mProperties.erase(it);
     423                }
     424        }
     425    }
     426
     427    /*
     428     * If something went wrong then rollback.  This is possible because we
     429     * haven't deleted anything yet.
     430     */
     431    if (RT_FAILURE(rc))
     432    {
     433        if (itEnd != mProperties.end())
     434            ++itEnd;
     435        mProperties.erase(itEnd, mProperties.end());
     436    }
     437    return rc;
     438}
    307439
    308440/**
     
    318450 * @thread  HGCM
    319451 */
    320 int Service::getPropValue(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
     452int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    321453{
    322454    int rc = VINF_SUCCESS;
    323     char *pszName, *pszValue;
    324     uint32_t cbName, cbValue;
    325     size_t cbValueActual;
    326 
    327     LogFlowThisFunc(("\n"));
    328     AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */
    329     if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */
    330         || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */
    331         || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* value */
    332        )
    333         rc = VERR_INVALID_PARAMETER;
    334     if (RT_SUCCESS(rc))
    335         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName);
    336     if (RT_SUCCESS(rc))
    337         rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cbValue);
    338     if (RT_SUCCESS(rc))
    339         rc = validateName(pszName, cbName);
    340     if (RT_SUCCESS(rc))
    341         rc = CFGMR3QuerySize(mpValueNode, pszName, &cbValueActual);
    342     if (RT_SUCCESS(rc))
    343         VBoxHGCMParmUInt32Set(&paParms[2], cbValueActual);
    344     if (RT_SUCCESS(rc) && (cbValueActual > cbValue))
    345         rc = VERR_BUFFER_OVERFLOW;
    346     if (RT_SUCCESS(rc))
    347         rc = CFGMR3QueryString(mpValueNode, pszName, pszValue, cbValue);
    348     if (RT_SUCCESS(rc))
    349         Log2(("Queried string %s, rc=%Rrc, value=%.*s\n", pszName, rc, cbValue, pszValue));
    350     else if (VERR_CFGM_VALUE_NOT_FOUND == rc)
    351         rc = VERR_NOT_FOUND;
    352     LogFlowThisFunc(("rc = %Rrc\n", rc));
    353     return rc;
    354 }
    355 
    356 
    357 /**
    358  * Retrieve a value from the property registry by name, checking the validity
    359  * of the arguments passed.  If the guest has not allocated enough buffer
    360  * space for the value then we return VERR_OVERFLOW and set the size of the
    361  * buffer needed in the "size" HGCM parameter.  If the name was not found at
    362  * all, we return VERR_NOT_FOUND.
    363  *
    364  * @returns iprt status value
    365  * @param   cParms  the number of HGCM parameters supplied
    366  * @param   paParms the array of HGCM parameters
    367  * @thread  HGCM
    368  */
    369 int Service::getProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    370 {
    371     int rc = VINF_SUCCESS;
    372     char *pszName, *pchBuf;
     455    const char *pcszName;
     456    char *pchBuf;
    373457    uint32_t cchName, cchBuf;
    374     size_t cchValue, cchFlags, cchBufActual;
     458    size_t cchFlags, cchBufActual;
    375459    char szFlags[MAX_FLAGS_LEN];
    376460    uint32_t fFlags;
     
    380464     */
    381465    LogFlowThisFunc(("\n"));
    382     AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */
    383466    if (   (cParms != 4)  /* Hardcoded value as the next lines depend on it. */
    384467        || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)    /* name */
     
    387470        rc = VERR_INVALID_PARAMETER;
    388471    if (RT_SUCCESS(rc))
    389         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName);
     472        rc = VBoxHGCMParmPtrConstGet(&paParms[0], (const void **) &pcszName, &cchName);
    390473    if (RT_SUCCESS(rc))
    391474        rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf);
    392475    if (RT_SUCCESS(rc))
    393         rc = validateName(pszName, cchName);
     476        rc = validateName(pcszName, cchName);
    394477
    395478    /*
     
    398481
    399482    /* Get the value size */
    400     if (RT_SUCCESS(rc))
    401         rc = CFGMR3QuerySize(mpValueNode, pszName, &cchValue);
    402     /* Get the flags and their size */
    403     if (RT_SUCCESS(rc))
    404         CFGMR3QueryU32(mpFlagsNode, pszName, (uint32_t *)&fFlags);
    405     if (RT_SUCCESS(rc))
    406         rc = writeFlags(fFlags, szFlags);
     483    PropertyList::const_iterator it;
     484    bool found = false;
     485    if (RT_SUCCESS(rc))
     486        for (it = mProperties.begin(); it != mProperties.end(); ++it)
     487            if (it->mName.compare(pcszName) == 0)
     488            {
     489                found = true;
     490                break;
     491            }
     492    if (RT_SUCCESS(rc) && !found)
     493        rc = VERR_NOT_FOUND;
     494    if (RT_SUCCESS(rc))
     495        rc = writeFlags(it->mFlags, szFlags);
    407496    if (RT_SUCCESS(rc))
    408497        cchFlags = strlen(szFlags);
     
    410499    if (RT_SUCCESS(rc))
    411500    {
    412         cchBufActual = cchValue + cchFlags;
     501        cchBufActual = it->mValue.size() + 1 + cchFlags;
    413502        VBoxHGCMParmUInt32Set(&paParms[3], cchBufActual);
    414503    }
    415504    if (RT_SUCCESS(rc) && (cchBufActual > cchBuf))
    416505        rc = VERR_BUFFER_OVERFLOW;
    417     /* Write the value */
    418     if (RT_SUCCESS(rc))
    419         rc = CFGMR3QueryString(mpValueNode, pszName, pchBuf, cchBuf);
    420     /* Write the flags */
    421     if (RT_SUCCESS(rc))
    422         strcpy(pchBuf + cchValue, szFlags);
    423     /* Timestamp */
    424     uint64_t u64Timestamp = 0;
    425     if (RT_SUCCESS(rc))
    426         CFGMR3QueryU64(mpTimestampNode, pszName, &u64Timestamp);
    427     VBoxHGCMParmUInt64Set(&paParms[2], u64Timestamp);
     506    /* Write the value, flags and timestamp */
     507    if (RT_SUCCESS(rc))
     508    {
     509        it->mValue.copy(pchBuf, cchBuf, 0);
     510        pchBuf[it->mValue.size()] = '\0'; /* Terminate the value */
     511        strcpy(pchBuf + it->mValue.size() + 1, szFlags);
     512        VBoxHGCMParmUInt64Set(&paParms[2], it->mTimestamp);
     513    }
    428514
    429515    /*
     
    431517     */
    432518    if (RT_SUCCESS(rc))
    433         Log2(("Queried string %S, value=%.*S, timestamp=%lld, flags=%.*S\n",
    434               pszName, cchValue, pchBuf, u64Timestamp, cchFlags,
    435               pchBuf + cchValue));
    436     else if (VERR_CFGM_VALUE_NOT_FOUND == rc)
    437         rc = VERR_NOT_FOUND;
     519        Log2(("Queried string %s, value=%s, timestamp=%lld, flags=%s\n",
     520              pcszName, it->mValue.c_str(), it->mTimestamp, szFlags));
    438521    LogFlowThisFunc(("rc = %Rrc\n", rc));
    439522    return rc;
    440523}
    441524
    442 
    443525/**
    444526 * Set a value in the property registry by name, checking the validity
     527 * of the arguments passed.
     528 *
     529 * @returns iprt status value
     530 * @param   cParms  the number of HGCM parameters supplied
     531 * @param   paParms the array of HGCM parameters
     532 * @param   isGuest is this call coming from the guest (or the host)?
     533 * @throws  std::bad_alloc  if an out of memory condition occurs
     534 * @thread  HGCM
     535 */
     536int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
     537{
     538    int rc = VINF_SUCCESS;
     539    const char *pcszName, *pcszValue, *pcszFlags = NULL;
     540    uint32_t cchName, cchValue, cchFlags = 0;
     541    uint32_t fFlags = NILFLAG;
     542
     543    LogFlowThisFunc(("\n"));
     544    /*
     545     * First of all, make sure that we won't exceed the maximum number of properties.
     546     */
     547    if (mProperties.size() >= MAX_PROPS)
     548        rc = VERR_TOO_MUCH_DATA;
     549
     550    /*
     551     * General parameter correctness checking.
     552     */
     553    if (   RT_SUCCESS(rc)
     554        && (   (cParms < 2) || (cParms > 3)  /* Hardcoded value as the next lines depend on it. */
     555            || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0],
     556                   (const void **) &pcszName, &cchName)) /* name */
     557            || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[1],
     558                   (const void **) &pcszValue, &cchValue)) /* value */
     559            || (   (3 == cParms)
     560                && RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[2],
     561                       (const void **) &pcszFlags, &cchFlags)) /* flags */
     562               )
     563           )
     564       )
     565        rc = VERR_INVALID_PARAMETER;
     566
     567    /*
     568     * Check the values passed in the parameters for correctness.
     569     */
     570    if (RT_SUCCESS(rc))
     571        rc = validateName(pcszName, cchName);
     572    if (RT_SUCCESS(rc))
     573        rc = validateValue(pcszValue, cchValue);
     574    if ((3 == cParms) && RT_SUCCESS(rc))
     575        rc = RTStrValidateEncodingEx(pcszFlags, cchFlags,
     576                                     RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED);
     577    if ((3 == cParms) && RT_SUCCESS(rc))
     578        rc = validateFlags(pcszFlags, &fFlags);
     579
     580    /*
     581     * If the property already exists, check its flags to see if we are allowed
     582     * to change it.
     583     */
     584    PropertyList::iterator it;
     585    bool found = false;
     586    if (RT_SUCCESS(rc))
     587        for (it = mProperties.begin(); it != mProperties.end(); ++it)
     588            if (it->mName.compare(pcszName) == 0)
     589            {
     590                found = true;
     591                break;
     592            }
     593    if (RT_SUCCESS(rc) && found)
     594        if (   (isGuest && (it->mFlags & RDONLYGUEST))
     595            || (!isGuest && (it->mFlags & RDONLYHOST))
     596           )
     597            rc = VERR_PERMISSION_DENIED;
     598
     599    /*
     600     * Set the actual value
     601     */
     602    if (RT_SUCCESS(rc))
     603    {
     604        RTTIMESPEC time;
     605        uint64_t u64TimeNano = RTTimeSpecGetNano(RTTimeNow(&time));
     606        if (found)
     607        {
     608            it->mValue = pcszValue;
     609            it->mTimestamp = u64TimeNano;
     610            it->mFlags = fFlags;
     611        }
     612        else  /* This can throw.  No problem as we have nothing to roll back. */
     613            mProperties.push_back(Property(pcszName, pcszValue, u64TimeNano, fFlags));
     614    }
     615
     616    /*
     617     * Send a notification to the host and return.
     618     */
     619    if (RT_SUCCESS(rc))
     620    {
     621        // if (isGuest)  /* Notify the host even for properties that the host
     622        //                * changed.  Less efficient, but ensures consistency. */
     623            notifyHost(pcszName);
     624        Log2(("Set string %s, rc=%Rrc, value=%s\n", pcszName, rc, pcszValue));
     625    }
     626    LogFlowThisFunc(("rc = %Rrc\n", rc));
     627    return rc;
     628}
     629
     630
     631/**
     632 * Remove a value in the property registry by name, checking the validity
     633 * of the arguments passed.
     634 *
     635 * @returns iprt status value
     636 * @param   cParms  the number of HGCM parameters supplied
     637 * @param   paParms the array of HGCM parameters
     638 * @param   isGuest is this call coming from the guest (or the host)?
     639 * @thread  HGCM
     640 */
     641int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
     642{
     643    int rc = VINF_SUCCESS;
     644    const char *pcszName;
     645    uint32_t cbName;
     646
     647    LogFlowThisFunc(("\n"));
     648
     649    /*
     650     * Check the user-supplied parameters.
     651     */
     652    if (   (cParms != 1)  /* Hardcoded value as the next lines depend on it. */
     653        || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0],
     654               (const void **) &pcszName, &cbName))  /* name */
     655       )
     656        rc = VERR_INVALID_PARAMETER;
     657    if (RT_SUCCESS(rc))
     658        rc = validateName(pcszName, cbName);
     659
     660    /*
     661     * If the property exists, check its flags to see if we are allowed
     662     * to change it.
     663     */
     664    PropertyList::iterator it;
     665    bool found = false;
     666    if (RT_SUCCESS(rc))
     667        for (it = mProperties.begin(); it != mProperties.end(); ++it)
     668            if (it->mName.compare(pcszName) == 0)
     669            {
     670                found = true;
     671                break;
     672            }
     673    if (RT_SUCCESS(rc) && found)
     674        if (   (isGuest && (it->mFlags & RDONLYGUEST))
     675            || (!isGuest && (it->mFlags & RDONLYHOST))
     676           )
     677            rc = VERR_PERMISSION_DENIED;
     678
     679    /*
     680     * And delete the property if all is well.
     681     */
     682    if (RT_SUCCESS(rc) && found)
     683    {
     684        mProperties.erase(it);
     685        // if (isGuest)  /* Notify the host even for properties that the host
     686        //                * changed.  Less efficient, but ensures consistency. */
     687            notifyHost(pcszName);
     688    }
     689    LogFlowThisFunc(("rc = %Rrc\n", rc));
     690    return rc;
     691}
     692
     693/**
     694 * Enumerate guest properties by mask, checking the validity
    445695 * of the arguments passed.
    446696 *
     
    450700 * @thread  HGCM
    451701 */
    452 int Service::setProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
     702int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    453703{
    454704    int rc = VINF_SUCCESS;
    455     char *pszName, *pszValue;
    456     uint32_t cchName, cchValue;
    457     uint32_t fFlags = NILFLAG;
    458 
     705
     706    /*
     707     * Get the HGCM function arguments.
     708     */
     709    char *pcchPatterns = NULL, *pchBuf = NULL;
     710    uint32_t cchPatterns = 0, cchBuf = 0;
    459711    LogFlowThisFunc(("\n"));
    460     AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */
    461     /*
    462      * First of all, make sure that we won't exceed the maximum number of properties.
    463      */
    464     {
    465         unsigned cChildren = 0;
    466         for (PCFGMNODE pChild = CFGMR3GetFirstChild(mpValueNode); pChild != 0; pChild = CFGMR3GetNextChild(pChild))
    467             ++cChildren;
    468         if (cChildren >= MAX_PROPS)
    469             rc = VERR_TOO_MUCH_DATA;
    470     }
    471     /*
    472      * General parameter correctness checking.
    473      */
    474     if (   RT_SUCCESS(rc)
    475         && (   (cParms < 2) || (cParms > 4)  /* Hardcoded value as the next lines depend on it. */
    476             || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */
    477             || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* value */
    478             || ((3 == cParms) && (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR))  /* flags */
    479            )
     712    if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */
     713        || RT_FAILURE(VBoxHGCMParmPtrConstGet(&paParms[0],
     714               (const void **) &pcchPatterns, &cchPatterns))  /* patterns */
     715        || RT_FAILURE(VBoxHGCMParmPtrGet(&paParms[1],
     716               (void **) &pchBuf, &cchBuf))  /* return buffer */
    480717       )
    481718        rc = VERR_INVALID_PARAMETER;
    482     /*
    483      * Check the values passed in the parameters for correctness.
    484      */
    485     if (RT_SUCCESS(rc))
    486         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cchName);
    487     if (RT_SUCCESS(rc))
    488         rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pszValue, &cchValue);
    489     if (RT_SUCCESS(rc))
    490         rc = validateName(pszName, cchName);
    491     if (RT_SUCCESS(rc))
    492         rc = validateValue(pszValue, cchValue);
    493 
    494     /*
    495      * If the property already exists, check its flags to see if we are allowed
    496      * to change it.
    497      */
    498     if (RT_SUCCESS(rc))
    499     {
    500         CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags);  /* Failure is no problem here. */
    501         if (   (isGuest && (fFlags & RDONLYGUEST))
    502             || (!isGuest && (fFlags & RDONLYHOST))
    503            )
    504             rc = VERR_PERMISSION_DENIED;
    505     }
    506 
    507     /*
    508      * Check whether the user supplied flags (if any) are valid.
    509      */
    510     if (RT_SUCCESS(rc) && (3 == cParms))
    511     {
    512         char *pszFlags;
    513         uint32_t cchFlags;
    514         rc = VBoxHGCMParmPtrGet(&paParms[2], (void **) &pszFlags, &cchFlags);
    515         if (RT_SUCCESS(rc))
    516             rc = validateFlags(pszFlags, &fFlags);
    517     }
    518     /*
    519      * Set the actual value
    520      */
    521     if (RT_SUCCESS(rc))
    522     {
    523         RTTIMESPEC time;
    524         CFGMR3RemoveValue(mpValueNode, pszName);
    525         CFGMR3RemoveValue(mpTimestampNode, pszName);
    526         CFGMR3RemoveValue(mpFlagsNode, pszName);
    527         rc = CFGMR3InsertString(mpValueNode, pszName, pszValue);
    528         if (RT_SUCCESS(rc))
    529             rc = CFGMR3InsertInteger(mpTimestampNode, pszName,
    530                                      RTTimeSpecGetNano(RTTimeNow(&time)));
    531         if (RT_SUCCESS(rc))
    532             rc = CFGMR3InsertInteger(mpFlagsNode, pszName, fFlags);
    533         /* If anything goes wrong, make sure that we leave a clean state
    534          * behind. */
    535         if (RT_FAILURE(rc))
    536         {
    537             CFGMR3RemoveValue(mpValueNode, pszName);
    538             CFGMR3RemoveValue(mpTimestampNode, pszName);
    539             CFGMR3RemoveValue(mpFlagsNode, pszName);
    540         }
    541     }
    542     /*
    543      * Send a notification to the host and return.
    544      */
    545     if (RT_SUCCESS(rc))
    546     {
    547         if (isGuest)
    548             notifyHost(pszName);
    549         Log2(("Set string %s, rc=%Rrc, value=%s\n", pszName, rc, pszValue));
    550     }
    551     LogFlowThisFunc(("rc = %Rrc\n", rc));
    552     return rc;
    553 }
    554 
    555 
    556 /**
    557  * Remove a value in the property registry by name, checking the validity
    558  * of the arguments passed.
    559  *
    560  * @returns iprt status value
    561  * @param   cParms  the number of HGCM parameters supplied
    562  * @param   paParms the array of HGCM parameters
    563  * @thread  HGCM
    564  */
    565 int Service::delProperty(uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool isGuest)
    566 {
    567     int rc = VINF_SUCCESS;
    568     char *pszName;
    569     uint32_t cbName;
    570 
    571     LogFlowThisFunc(("\n"));
    572     AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */
    573 
    574     /*
    575      * Check the user-supplied parameters.
    576      */
    577     if (   (cParms != 1)  /* Hardcoded value as the next lines depend on it. */
    578         || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* name */
    579        )
    580         rc = VERR_INVALID_PARAMETER;
    581     if (RT_SUCCESS(rc))
    582         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &pszName, &cbName);
    583     if (RT_SUCCESS(rc))
    584         rc = validateName(pszName, cbName);
    585 
    586     /*
    587      * If the property already exists, check its flags to see if we are allowed
    588      * to change it.
    589      */
    590     if (RT_SUCCESS(rc))
    591     {
    592         uint32_t fFlags = NILFLAG;
    593         CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags);  /* Failure is no problem here. */
    594         if (   (isGuest && (fFlags & RDONLYGUEST))
    595             || (!isGuest && (fFlags & RDONLYHOST))
    596            )
    597             rc = VERR_PERMISSION_DENIED;
    598     }
    599 
    600     /*
    601      * And delete the property if all is well.
    602      */
    603     if (RT_SUCCESS(rc))
    604     {
    605         CFGMR3RemoveValue(mpValueNode, pszName);
    606         if (isGuest)
    607             notifyHost(pszName);
    608     }
    609     LogFlowThisFunc(("rc = %Rrc\n", rc));
    610     return rc;
    611 }
    612 
    613 /**
    614  * Enumerate guest properties by mask, checking the validity
    615  * of the arguments passed.
    616  *
    617  * @returns iprt status value
    618  * @param   cParms  the number of HGCM parameters supplied
    619  * @param   paParms the array of HGCM parameters
    620  * @thread  HGCM
    621  */
    622 int Service::enumProps(uint32_t cParms, VBOXHGCMSVCPARM paParms[])
    623 {
    624     /* We reallocate the temporary buffer in which we build up our array in
    625      * increments of size BLOCK: */
    626     enum
    627     {
    628         /* Calculate the increment, not yet rounded down */
    629         BLOCKINCRFULL = (MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 2048),
    630         /* And this is the increment after rounding */
    631         BLOCKINCR = BLOCKINCRFULL - BLOCKINCRFULL % 1024
    632     };
    633     int rc = VINF_SUCCESS;
    634 
    635 /*
    636  * Get the HGCM function arguments.
    637  */
    638     char *paszPatterns = NULL, *pchBuf = NULL;
    639     uint32_t cchPatterns = 0, cchBuf = 0;
    640     LogFlowThisFunc(("\n"));
    641     AssertReturn(VALID_PTR(mpValueNode), VERR_WRONG_ORDER);  /* a.k.a. VERR_NOT_INITIALIZED */
    642     if (   (cParms != 3)  /* Hardcoded value as the next lines depend on it. */
    643         || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* patterns */
    644         || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* return buffer */
    645        )
    646         rc = VERR_INVALID_PARAMETER;
    647     if (RT_SUCCESS(rc))
    648         rc = VBoxHGCMParmPtrGet(&paParms[0], (void **) &paszPatterns, &cchPatterns);
    649719    if (RT_SUCCESS(rc) && cchPatterns > MAX_PATTERN_LEN)
    650720        rc = VERR_TOO_MUCH_DATA;
    651     if (RT_SUCCESS(rc))
    652         rc = VBoxHGCMParmPtrGet(&paParms[1], (void **) &pchBuf, &cchBuf);
    653 
    654 /*
    655  * First repack the patterns into the format expected by RTStrSimplePatternMatch()
    656  */
     721
     722    /*
     723     * First repack the patterns into the format expected by RTStrSimplePatternMatch()
     724     */
    657725    bool matchAll = false;
    658726    char pszPatterns[MAX_PATTERN_LEN];
    659     if (   (NULL == paszPatterns)
     727    if (   (NULL == pcchPatterns)
    660728        || (cchPatterns < 2)  /* An empty pattern string means match all */
    661729       )
     
    664732    {
    665733        for (unsigned i = 0; i < cchPatterns - 1; ++i)
    666             if (paszPatterns[i] != '\0')
    667                 pszPatterns[i] = paszPatterns[i];
     734            if (pcchPatterns[i] != '\0')
     735                pszPatterns[i] = pcchPatterns[i];
    668736            else
    669737                pszPatterns[i] = '|';
     
    671739    }
    672740
    673 /*
    674  * Next enumerate all values in the current node into a temporary buffer.
    675  */
    676     RTMemAutoPtr<char> TmpBuf;
    677     uint32_t cchTmpBuf = 0, iTmpBuf = 0;
    678     PCFGMLEAF pLeaf = CFGMR3GetFirstValue(mpValueNode);
    679     while ((pLeaf != NULL) && RT_SUCCESS(rc))
    680     {
    681         /* Reallocate the buffer if it has got too tight */
    682         if (iTmpBuf + BLOCKINCR > cchTmpBuf)
    683         {
    684             cchTmpBuf += BLOCKINCR * 2;
    685             if (!TmpBuf.realloc(cchTmpBuf))
    686                 rc = VERR_NO_MEMORY;
    687         }
    688         /* Fetch the name into the buffer and if it matches one of the
    689          * patterns, add its value and an empty timestamp and flags.  If it
    690          * doesn't match, we simply overwrite it in the buffer. */
    691         if (RT_SUCCESS(rc))
    692             rc = CFGMR3GetValueName(pLeaf, &TmpBuf[iTmpBuf], cchTmpBuf - iTmpBuf);
    693         /* Only increment the buffer offest if the name matches, otherwise we
    694          * overwrite it next iteration. */
    695         if (   RT_SUCCESS(rc)
    696             && (   matchAll
    697                 || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX,
    698                                                 &TmpBuf[iTmpBuf], RTSTR_MAX,
    699                                                 NULL)
    700                )
     741    /*
     742     * Next enumerate into a temporary buffer.  This can throw, but this is
     743     * not a problem as we have nothing to roll back.
     744     */
     745    std::string buffer;
     746    for (PropertyList::const_iterator it = mProperties.begin();
     747         RT_SUCCESS(rc) && (it != mProperties.end()); ++it)
     748    {
     749        if (   matchAll
     750            || RTStrSimplePatternMultiMatch(pszPatterns, RTSTR_MAX,
     751                                            it->mName.c_str(), RTSTR_MAX, NULL)
    701752           )
    702753        {
    703             const char *pszName = &TmpBuf[iTmpBuf];
    704             /* Get value */
    705             iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1;
    706             rc = CFGMR3QueryString(mpValueNode, pszName, &TmpBuf[iTmpBuf],
    707                                    cchTmpBuf - iTmpBuf);
     754            char szFlags[MAX_FLAGS_LEN];
     755            char szTimestamp[256];
     756            size_t cchTimestamp;
     757            buffer += it->mName;
     758            buffer += '\0';
     759            buffer += it->mValue;
     760            buffer += '\0';
     761            cchTimestamp = RTStrFormatNumber(szTimestamp, it->mTimestamp,
     762                                             10, 0, 0, 0);
     763            buffer.append(szTimestamp, cchTimestamp);
     764            buffer += '\0';
     765            rc = writeFlags(it->mFlags, szFlags);
    708766            if (RT_SUCCESS(rc))
    709             {
    710                 /* Get timestamp */
    711                 iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1;
    712                 uint64_t u64Timestamp = 0;
    713                 CFGMR3QueryU64(mpTimestampNode, pszName, &u64Timestamp);
    714                 iTmpBuf += RTStrFormatNumber(&TmpBuf[iTmpBuf], u64Timestamp,
    715                                              10, 0, 0, 0) + 1;
    716                 /* Get flags */
    717                 uint32_t fFlags = NILFLAG;
    718                 CFGMR3QueryU32(mpFlagsNode, pszName, &fFlags);
    719                 TmpBuf[iTmpBuf] = '\0';  /* Bad (== in)sanity, will be fixed. */
    720                 writeFlags(fFlags, &TmpBuf[iTmpBuf]);
    721                 iTmpBuf += strlen(&TmpBuf[iTmpBuf]) + 1;
    722             }
     767                buffer += szFlags;
     768            buffer += '\0';
    723769        }
    724         if (RT_SUCCESS(rc))
    725             pLeaf = CFGMR3GetNextValue(pLeaf);
    726     }
    727     if (RT_SUCCESS(rc))
    728     {
    729         /* The terminator.  We *do* have space left for this. */
    730         TmpBuf[iTmpBuf] = '\0';
    731         TmpBuf[iTmpBuf + 1] = '\0';
    732         TmpBuf[iTmpBuf + 2] = '\0';
    733         TmpBuf[iTmpBuf + 3] = '\0';
    734         iTmpBuf += 4;
    735         VBoxHGCMParmUInt32Set(&paParms[2], iTmpBuf);
     770    }
     771    buffer.append(4, '\0');  /* The final terminators */
     772
     773    /*
     774     * Finally write out the temporary buffer to the real one if it is not too
     775     * small.
     776     */
     777    if (RT_SUCCESS(rc))
     778    {
     779        VBoxHGCMParmUInt32Set(&paParms[2], buffer.size());
    736780        /* Copy the memory if it fits into the guest buffer */
    737         if (iTmpBuf <= cchBuf)
    738             memcpy(pchBuf, TmpBuf.get(), iTmpBuf);
     781        if (buffer.size() <= cchBuf)
     782            buffer.copy(pchBuf, cchBuf);
    739783        else
    740784            rc = VERR_BUFFER_OVERFLOW;
     
    753797void Service::notifyHost(const char *pszProperty)
    754798{
    755     char szValue[MAX_VALUE_LEN];
    756     uint64_t u64Timestamp = 0;
    757     uint32_t fFlags = NILFLAG;
     799#ifndef VBOX_GUEST_PROP_TEST_NOTHREAD
    758800    char szFlags[MAX_FLAGS_LEN];
    759801    char *pszName = NULL, *pszValue = NULL, *pszFlags = NULL;
    760 
    761     AssertPtr(mpValueNode);
     802    int rc = VINF_SUCCESS;
     803
    762804    if (NULL == mpfnHostCallback)
    763805        return;  /* Nothing to do. */
    764     int rc = CFGMR3QueryString(mpValueNode, pszProperty, szValue,
    765                                sizeof(szValue));
     806    PropertyList::const_iterator it;
     807    bool found = false;
     808    if (RT_SUCCESS(rc))
     809        for (it = mProperties.begin(); it != mProperties.end(); ++it)
     810            if (it->mName.compare(pszProperty) == 0)
     811            {
     812                found = true;
     813                break;
     814            }
    766815    /*
    767816     * First case: if the property exists then send the host its current value
    768817     */
    769     if (rc != VERR_CFGM_VALUE_NOT_FOUND)
    770     {
    771         if (RT_SUCCESS(rc))
    772             rc = CFGMR3QueryU64(mpTimestampNode, pszProperty, &u64Timestamp);
    773         if (RT_SUCCESS(rc))
    774             rc = CFGMR3QueryU32(mpFlagsNode, pszProperty, &fFlags);
    775         if (RT_SUCCESS(rc))
    776             rc = writeFlags(fFlags, szFlags);
     818    if (found)
     819    {
     820        rc = writeFlags(it->mFlags, szFlags);
    777821        if (RT_SUCCESS(rc))
    778822            rc = RTStrDupEx(&pszName, pszProperty);
    779823        if (RT_SUCCESS(rc))
    780             rc = RTStrDupEx(&pszValue, szValue);
     824            rc = RTStrDupEx(&pszValue, it->mValue.c_str());
    781825        if (RT_SUCCESS(rc))
    782826            rc = RTStrDupEx(&pszFlags, szFlags);
     
    785829                             (PFNRT)Service::reqNotify, 7, mpfnHostCallback,
    786830                             mpvHostData, pszName, pszValue,
    787                              (uint32_t) RT_HIDWORD(u64Timestamp),
    788                              (uint32_t) RT_LODWORD(u64Timestamp), pszFlags);
    789         if (RT_FAILURE(rc)) /* clean up */
    790         {
    791             RTStrFree(pszName);
    792             RTStrFree(pszValue);
    793             RTStrFree(pszFlags);
    794         }
     831                             (uint32_t) RT_HIDWORD(it->mTimestamp),
     832                             (uint32_t) RT_LODWORD(it->mTimestamp), pszFlags);
    795833    }
    796834    else
     
    812850        RTStrFree(pszFlags);
    813851    }
     852#endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */
    814853}
    815854
     
    861900                 u32ClientID, eFunction, cParms, paParms));
    862901
    863     switch (eFunction)
    864     {
    865         /* The guest wishes to read a property */
    866         case GET_PROP:
    867             LogFlowFunc(("GET_PROP\n"));
    868             rc = getProperty(cParms, paParms);
    869             break;
    870 
    871         /* The guest wishes to set a property */
    872         case SET_PROP:
    873             LogFlowFunc(("SET_PROP\n"));
    874             rc = setProperty(cParms, paParms, true);
    875             break;
    876 
    877         /* The guest wishes to set a property value */
    878         case SET_PROP_VALUE:
    879             LogFlowFunc(("SET_PROP_VALUE\n"));
    880             rc = setProperty(cParms, paParms, true);
    881             break;
    882 
    883         /* The guest wishes to remove a configuration value */
    884         case DEL_PROP:
    885             LogFlowFunc(("DEL_PROP\n"));
    886             rc = delProperty(cParms, paParms, true);
    887             break;
    888 
    889         /* The guest wishes to enumerate all properties */
    890         case ENUM_PROPS:
    891             LogFlowFunc(("ENUM_PROPS\n"));
    892             rc = enumProps(cParms, paParms);
    893             break;
    894         default:
    895             rc = VERR_NOT_IMPLEMENTED;
     902    try
     903    {
     904        switch (eFunction)
     905        {
     906            /* The guest wishes to read a property */
     907            case GET_PROP:
     908                LogFlowFunc(("GET_PROP\n"));
     909                rc = getProperty(cParms, paParms);
     910                break;
     911
     912            /* The guest wishes to set a property */
     913            case SET_PROP:
     914                LogFlowFunc(("SET_PROP\n"));
     915                rc = setProperty(cParms, paParms, true);
     916                break;
     917
     918            /* The guest wishes to set a property value */
     919            case SET_PROP_VALUE:
     920                LogFlowFunc(("SET_PROP_VALUE\n"));
     921                rc = setProperty(cParms, paParms, true);
     922                break;
     923
     924            /* The guest wishes to remove a configuration value */
     925            case DEL_PROP:
     926                LogFlowFunc(("DEL_PROP\n"));
     927                rc = delProperty(cParms, paParms, true);
     928                break;
     929
     930            /* The guest wishes to enumerate all properties */
     931            case ENUM_PROPS:
     932                LogFlowFunc(("ENUM_PROPS\n"));
     933                rc = enumProps(cParms, paParms);
     934                break;
     935
     936            default:
     937                rc = VERR_NOT_IMPLEMENTED;
     938        }
     939    }
     940    catch (std::bad_alloc)
     941    {
     942        rc = VERR_NO_MEMORY;
    896943    }
    897944    if (fCallSync)
     
    915962                 eFunction, cParms, paParms));
    916963
    917     switch (eFunction)
    918     {
    919         /* Set the root CFGM node used.  This should be called when instantiating
    920          * the service. */
    921         /* This whole case is due to go away, so I will not clean it up. */
    922         case SET_CFGM_NODE:
     964    try
     965    {
     966        switch (eFunction)
    923967        {
    924             LogFlowFunc(("SET_CFGM_NODE\n"));
    925 
    926             if (   (cParms != 3)
    927                 || (paParms[0].type != VBOX_HGCM_SVC_PARM_PTR)   /* pValue */
    928                 || (paParms[1].type != VBOX_HGCM_SVC_PARM_PTR)   /* pTimestamp */
    929                 || (paParms[2].type != VBOX_HGCM_SVC_PARM_PTR)   /* pFlags */
    930                )
    931                 rc = VERR_INVALID_PARAMETER;
    932             else
    933             {
    934                 PCFGMNODE pValue = NULL, pTimestamp = NULL, pFlags = NULL;
    935                 uint32_t cbDummy;
    936 
    937                 rc = VBoxHGCMParmPtrGet (&paParms[0], (void **) &pValue, &cbDummy);
    938                 if (RT_SUCCESS(rc))
    939                     rc = VBoxHGCMParmPtrGet (&paParms[1], (void **) &pTimestamp, &cbDummy);
    940                 if (RT_SUCCESS(rc))
    941                     rc = VBoxHGCMParmPtrGet (&paParms[2], (void **) &pFlags, &cbDummy);
    942                 if (RT_SUCCESS(rc))
    943                 {
    944                     mpValueNode     = pValue;
    945                     mpTimestampNode = pTimestamp;
    946                     mpFlagsNode     = pFlags;
    947                 }
    948             }
    949         } break;
    950 
    951         /* The host wishes to read a configuration value */
    952         case GET_PROP_HOST:
    953             LogFlowFunc(("GET_PROP_HOST\n"));
    954             rc = getProperty(cParms, paParms);
    955             break;
    956 
    957         /* The host wishes to set a configuration value */
    958         case SET_PROP_HOST:
    959             LogFlowFunc(("SET_PROP_HOST\n"));
    960             rc = setProperty(cParms, paParms, false);
    961             break;
    962 
    963         /* The host wishes to set a configuration value */
    964         case SET_PROP_VALUE_HOST:
    965             LogFlowFunc(("SET_PROP_VALUE_HOST\n"));
    966             rc = setProperty(cParms, paParms, false);
    967             break;
    968 
    969         /* The host wishes to remove a configuration value */
    970         case DEL_PROP_HOST:
    971             LogFlowFunc(("DEL_PROP_HOST\n"));
    972             rc = delProperty(cParms, paParms, false);
    973             break;
    974 
    975         /* The host wishes to enumerate all properties */
    976         case ENUM_PROPS_HOST:
    977             LogFlowFunc(("ENUM_PROPS\n"));
    978             rc = enumProps(cParms, paParms);
    979             break;
    980         default:
    981             rc = VERR_NOT_SUPPORTED;
    982             break;
     968            /* The host wishes to set a block of properties */
     969            case SET_PROPS_HOST:
     970                LogFlowFunc(("SET_PROPS_HOST\n"));
     971                rc = setPropertyBlock(cParms, paParms);
     972                break;
     973
     974            /* The host wishes to read a configuration value */
     975            case GET_PROP_HOST:
     976                LogFlowFunc(("GET_PROP_HOST\n"));
     977                rc = getProperty(cParms, paParms);
     978                break;
     979
     980            /* The host wishes to set a configuration value */
     981            case SET_PROP_HOST:
     982                LogFlowFunc(("SET_PROP_HOST\n"));
     983                rc = setProperty(cParms, paParms, false);
     984                break;
     985
     986            /* The host wishes to set a configuration value */
     987            case SET_PROP_VALUE_HOST:
     988                LogFlowFunc(("SET_PROP_VALUE_HOST\n"));
     989                rc = setProperty(cParms, paParms, false);
     990                break;
     991
     992            /* The host wishes to remove a configuration value */
     993            case DEL_PROP_HOST:
     994                LogFlowFunc(("DEL_PROP_HOST\n"));
     995                rc = delProperty(cParms, paParms, false);
     996                break;
     997
     998            /* The host wishes to enumerate all properties */
     999            case ENUM_PROPS_HOST:
     1000                LogFlowFunc(("ENUM_PROPS\n"));
     1001                rc = enumProps(cParms, paParms);
     1002                break;
     1003
     1004            default:
     1005                rc = VERR_NOT_SUPPORTED;
     1006                break;
     1007        }
     1008    }
     1009    catch (std::bad_alloc)
     1010    {
     1011        rc = VERR_NO_MEMORY;
    9831012    }
    9841013
     
    9891018int Service::uninit()
    9901019{
    991     int rc;
     1020    int rc = VINF_SUCCESS;
    9921021    unsigned count = 0;
    9931022
    9941023    mfExitThread = true;
     1024#ifndef VBOX_GUEST_PROP_TEST_NOTHREAD
    9951025    rc = RTReqCallEx(mReqQueue, NULL, 0, RTREQFLAGS_NO_WAIT, (PFNRT)reqVoid, 0);
    9961026    if (RT_SUCCESS(rc))
     
    10011031            Assert(RT_SUCCESS(rc) || ((VERR_TIMEOUT == rc) && (count != 5)));
    10021032        } while ((VERR_TIMEOUT == rc) && (count < 300));
     1033#endif /* VBOX_GUEST_PROP_TEST_NOTHREAD not defined */
    10031034    if (RT_SUCCESS(rc))
    10041035        RTReqDestroyQueue(mReqQueue);
  • trunk/src/VBox/HostServices/GuestProperties/testcase/Makefile.kmk

    r13629 r13759  
    2929PROGRAMS += tstGuestPropSvc
    3030tstGuestPropSvc_TEMPLATE = VBOXR3TSTEXE
    31 tstGuestPropSvc_DEFS     = VBOX_WITH_HGCM
    32 tstGuestPropSvc_SOURCES  = tstGuestPropSvc.cpp
     31# The second define here is to ensure that the testcase will run fast, without
     32# waiting for any thread synchronisation.
     33tstGuestPropSvc_DEFS     = VBOX_WITH_HGCM VBOX_GUEST_PROP_TEST_NOTHREAD
     34tstGuestPropSvc_SOURCES  = tstGuestPropSvc.cpp ../service.cpp
    3335tstGuestPropSvc_LIBS     = $(LIB_RUNTIME)
     36
     37# Set this in LocalConfig.kmk if you are working on the guest property service
     38# to automatically run the testcase at build time.
     39ifdef VBOX_RUN_GUEST_PROPERTY_TEST
     40 ifndef VBOX_ONLY_SDK
     41  TESTING  += $(PATH_tstGuestPropSvc)/tstGuestPropSvc.run
     42  OTHERS += $(PATH_tstGuestPropSvc)/tstGuestPropSvc.run
     43$$(PATH_tstGuestPropSvc)/tstGuestPropSvc.run: $$(INSTARGET_tstGuestPropSvc)
     44        $(INSTARGET_tstGuestPropSvc) quiet
     45        $(QUIET)$(APPEND) -t "$@" "done"
     46 endif
     47endif
    3448
    3549endif # VBOX_WITH_TESTCASES
  • trunk/src/VBox/HostServices/GuestProperties/testcase/tstGuestPropSvc.cpp

    r13627 r13759  
    22/** @file
    33 *
    4  * Testcase for the guest property service.  For now, this only tests
    5  * flag conversion.
     4 * Testcase for the guest property service.
    65 */
    76
     
    3130using namespace guestProp;
    3231
    33 /**
    34  * A list of valid flag strings.  The flag conversion functions should accept
    35  * these and convert them from string to a flag type and back without errors.
     32extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable);
     33
     34/** Set a pointer value to an HGCM parameter structure */
     35static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb)
     36{
     37    pParm->type = VBOX_HGCM_SVC_PARM_PTR;
     38    pParm->u.pointer.addr = pv;
     39    pParm->u.pointer.size = cb;
     40}
     41
     42/** Extract a uint64_t value from an HGCM parameter structure */
     43static int VBoxHGCMParmUInt32Get (VBOXHGCMSVCPARM *pParm, uint32_t *pu32Value)
     44{
     45    if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT)
     46    {
     47        *pu32Value = pParm->u.uint32;
     48        return VINF_SUCCESS;
     49    }
     50
     51    return VERR_INVALID_PARAMETER;
     52}
     53
     54/** Extract a uint64_t value from an HGCM parameter structure */
     55static int VBoxHGCMParmUInt64Get (VBOXHGCMSVCPARM *pParm, uint64_t *pu64Value)
     56{
     57    if (pParm->type == VBOX_HGCM_SVC_PARM_64BIT)
     58    {
     59        *pu64Value = pParm->u.uint64;
     60        return VINF_SUCCESS;
     61    }
     62
     63    return VERR_INVALID_PARAMETER;
     64}
     65
     66/** Simple call handle structure for the guest call completion callback */
     67struct VBOXHGCMCALLHANDLE_TYPEDEF
     68{
     69    /** Where to store the result code */
     70    int32_t rc;
     71};
     72
     73/** Call completion callback for guest calls. */
     74static void callComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc)
     75{
     76    callHandle->rc = rc;
     77}
     78
     79/**
     80 * Initialise the HGCM service table as much as we need to start the
     81 * service
     82 * @param  pTable the table to initialise
     83 */
     84void initTable(VBOXHGCMSVCFNTABLE *pTable, VBOXHGCMSVCHELPERS *pHelpers)
     85{
     86    pTable->cbSize = sizeof (VBOXHGCMSVCFNTABLE);
     87    pTable->u32Version = VBOX_HGCM_SVC_VERSION;
     88    pHelpers->pfnCallComplete = callComplete;
     89    pTable->pHelpers = pHelpers;
     90}
     91
     92/**
     93 * A list of valid flag strings for testConvertFlags.  The flag conversion
     94 * functions should accept these and convert them from string to a flag type
     95 * and back without errors.
    3696 */
    3797struct flagStrings
     
    44104validFlagStrings[] =
    45105{
    46     { "", "" },
     106    { "  ", "" },
    47107    { "transient, ", "TRANSIENT" },
    48     { "  rdOnLyHOST, transIENT  ,     READONLY    ", "TRANSIENT, READONLY" }
    49 };
    50 
     108    { "  rdOnLyHOST, transIENT  ,     READONLY    ", "TRANSIENT, READONLY" },
     109    { " rdonlyguest", "RDONLYGUEST" },
     110    { "rdonlyhost     ", "RDONLYHOST" }
     111};
     112
     113/**
     114 * A list of invalid flag strings for testConvertFlags.  The flag conversion
     115 * functions should reject these.
     116 */
     117const char *invalidFlagStrings[] =
     118{
     119    "RDONLYHOST,,",
     120    "  TRANSIENT READONLY"
     121};
     122
     123/**
     124 * Test the flag conversion functions.
     125 * @returns iprt status value to indicate whether the test went as expected.
     126 * @note    prints its own diagnostic information to stdout.
     127 */
    51128int testConvertFlags()
    52129{
     
    55132    for (unsigned i = 0; i < RT_ELEMENTS(validFlagStrings) && RT_SUCCESS(rc); ++i)
    56133    {
    57         char szFlagBuffer[MAX_FLAGS_LEN];
     134        char szFlagBuffer[MAX_FLAGS_LEN * 2];
    58135        uint32_t fFlags;
    59136        rc = validateFlags(validFlagStrings[i].pcszIn, &fFlags);
    60137        if (RT_FAILURE(rc))
    61             RTPrintf("tstGuestPropSvc: FAILURE - Failed to validate flag string %s.\n", validFlagStrings[i].pcszIn);
     138            RTPrintf("tstGuestPropSvc: FAILURE - Failed to validate flag string '%s'.\n", validFlagStrings[i].pcszIn);
    62139        if (RT_SUCCESS(rc))
    63140        {
    64141            rc = writeFlags(fFlags, szFlagBuffer);
    65142            if (RT_FAILURE(rc))
    66                 RTPrintf("tstGuestPropSvc: FAILURE - Failed to convert flag string %s back to a string.\n",
     143                RTPrintf("tstGuestPropSvc: FAILURE - Failed to convert flag string '%s' back to a string.\n",
    67144                            validFlagStrings[i].pcszIn);
    68145        }
    69146        if (RT_SUCCESS(rc) && (strlen(szFlagBuffer) > MAX_FLAGS_LEN - 1))
    70147        {
    71             RTPrintf("tstGuestPropSvc: FAILURE - String %s converts back to a flag string which is too long.\n",
     148            RTPrintf("tstGuestPropSvc: FAILURE - String '%s' converts back to a flag string which is too long.\n",
    72149                        validFlagStrings[i].pcszIn);
    73150            rc = VERR_TOO_MUCH_DATA;
     
    75152        if (RT_SUCCESS(rc) && (strcmp(szFlagBuffer, validFlagStrings[i].pcszOut) != 0))
    76153        {
    77             RTPrintf("tstGuestPropSvc: FAILURE - String %s converts back to %s instead of to %s\n",
     154            RTPrintf("tstGuestPropSvc: FAILURE - String '%s' converts back to '%s' instead of to '%s'\n",
    78155                        validFlagStrings[i].pcszIn, szFlagBuffer,
    79156                        validFlagStrings[i].pcszOut);
     
    81158        }
    82159    }
     160    if (RT_SUCCESS(rc))
     161    {
     162        RTPrintf("Testing rejection of invalid flags strings.\n");
     163        for (unsigned i = 0; i < RT_ELEMENTS(invalidFlagStrings) && RT_SUCCESS(rc); ++i)
     164        {
     165            uint32_t fFlags;
     166            /* This is required to fail. */
     167            if (RT_SUCCESS(validateFlags(invalidFlagStrings[i], &fFlags)))
     168            {
     169                RTPrintf("String '%s' was incorrectly accepted as a valid flag string.\n",
     170                         invalidFlagStrings[i]);
     171                rc = VERR_PARSE_ERROR;
     172            }
     173        }
     174    }
     175    if (RT_SUCCESS(rc))
     176    {
     177        char szFlagBuffer[MAX_FLAGS_LEN * 2];
     178        uint32_t u32BadFlags = ALLFLAGS << 1;
     179        RTPrintf("Testing rejection of an invalid flags field.\n");
     180        /* This is required to fail. */
     181        if (RT_SUCCESS(writeFlags(u32BadFlags, szFlagBuffer)))
     182        {
     183            RTPrintf("Flags 0x%x were incorrectly written out as '%.*s'\n",
     184                     u32BadFlags, MAX_FLAGS_LEN, szFlagBuffer);
     185            rc = VERR_PARSE_ERROR;
     186        }
     187    }
    83188    return rc;
    84189}
    85190
     191/**
     192 * List of property names for testSetPropsHost.
     193 */
     194const char *apcszNameBlock[] =
     195{
     196    "test/name/",
     197    "test name",
     198    "TEST NAME",
     199    "/test/name",
     200    NULL
     201};
     202
     203/**
     204 * List of property values for testSetPropsHost.
     205 */
     206const char *apcszValueBlock[] =
     207{
     208    "test/value/",
     209    "test value",
     210    "TEST VALUE",
     211    "/test/value",
     212    NULL
     213};
     214
     215/**
     216 * List of property timestamps for testSetPropsHost.
     217 */
     218uint64_t au64TimestampBlock[] =
     219{
     220    0, 999, 999999, 999999999999, 0
     221};
     222
     223/**
     224 * List of property flags for testSetPropsHost.
     225 */
     226const char *apcszFlagsBlock[] =
     227{
     228    "",
     229    "readonly, transient",
     230    "RDONLYHOST",
     231    "RdOnlyGuest",
     232    NULL
     233};
     234
     235/**
     236 * Test the SET_PROPS_HOST function.
     237 * @returns iprt status value to indicate whether the test went as expected.
     238 * @note    prints its own diagnostic information to stdout.
     239 */
     240int testSetPropsHost(VBOXHGCMSVCFNTABLE *ptable)
     241{
     242    int rc = VINF_SUCCESS;
     243    RTPrintf("Testing the SET_PROPS_HOST call.\n");
     244    if (!VALID_PTR(ptable->pfnHostCall))
     245    {
     246        RTPrintf("Invalid pfnHostCall() pointer\n");
     247        rc = VERR_INVALID_POINTER;
     248    }
     249    if (RT_SUCCESS(rc))
     250    {
     251        VBOXHGCMSVCPARM paParms[4];
     252        VBoxHGCMParmPtrSet(&paParms[0], (void *) apcszNameBlock, 0);
     253        VBoxHGCMParmPtrSet(&paParms[1], (void *) apcszValueBlock, 0);
     254        VBoxHGCMParmPtrSet(&paParms[2], (void *) au64TimestampBlock, 0);
     255        VBoxHGCMParmPtrSet(&paParms[3], (void *) apcszFlagsBlock, 0);
     256        rc = ptable->pfnHostCall(ptable->pvService, SET_PROPS_HOST, 4,
     257                                 paParms);
     258        if (RT_FAILURE(rc))
     259            RTPrintf("SET_PROPS_HOST call failed with rc=%Rrc\n", rc);
     260    }
     261    return rc;
     262}
     263
     264/** Result strings for zeroth enumeration test */
     265static const char *pcchEnumResult0[] =
     266{
     267    "test/name/\0test/value/\0""0\0",
     268    "test name\0test value\0""999\0TRANSIENT, READONLY",
     269    "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST",
     270    "/test/name\0/test/value\0""999999999999\0RDONLYGUEST",
     271    NULL
     272};
     273
     274/** Result string sizes for zeroth enumeration test */
     275static const size_t cchEnumResult0[] =
     276{
     277    sizeof("test/name/\0test/value/\0""0\0"),
     278    sizeof("test name\0test value\0""999\0TRANSIENT, READONLY"),
     279    sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"),
     280    sizeof("/test/name\0/test/value\0""999999999999\0RDONLYGUEST"),
     281    0
     282};
     283
     284/**
     285 * The size of the buffer returned by the zeroth enumeration test -
     286 * the - 1 at the end is because of the hidden zero terminator
     287 */
     288static const size_t cchEnumBuffer0 =
     289sizeof("test/name/\0test/value/\0""0\0\0"
     290"test name\0test value\0""999\0TRANSIENT, READONLY\0"
     291"TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"
     292"/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1;
     293
     294/** Result strings for first and second enumeration test */
     295static const char *pcchEnumResult1[] =
     296{
     297    "TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST",
     298    "/test/name\0/test/value\0""999999999999\0RDONLYGUEST",
     299    NULL
     300};
     301
     302/** Result string sizes for first and second enumeration test */
     303static const size_t cchEnumResult1[] =
     304{
     305    sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST"),
     306    sizeof("/test/name\0/test/value\0""999999999999\0RDONLYGUEST"),
     307    0
     308};
     309
     310/**
     311 * The size of the buffer returned by the first enumeration test -
     312 * the - 1 at the end is because of the hidden zero terminator
     313 */
     314static const size_t cchEnumBuffer1 =
     315sizeof("TEST NAME\0TEST VALUE\0""999999\0RDONLYHOST\0"
     316"/test/name\0/test/value\0""999999999999\0RDONLYGUEST\0\0\0\0\0") - 1;
     317
     318static const struct enumStringStruct
     319{
     320    /** The enumeration pattern to test */
     321    const char *pcszPatterns;
     322    /** The size of the pattern string */
     323    const size_t cchPatterns;
     324    /** The expected enumeration output strings */
     325    const char **ppcchResult;
     326    /** The size of the output strings */
     327    const size_t *pcchResult;
     328    /** The size of the buffer needed for the enumeration */
     329    const size_t cchBuffer;
     330}
     331enumStrings[] =
     332{
     333    {
     334        "", sizeof(""),
     335        pcchEnumResult0,
     336        cchEnumResult0,
     337        cchEnumBuffer0
     338    },
     339    {
     340        "/*\0?E*", sizeof("/*\0?E*"),
     341        pcchEnumResult1,
     342        cchEnumResult1,
     343        cchEnumBuffer1
     344    },
     345    {
     346        "/*|?E*", sizeof("/*|?E*"),
     347        pcchEnumResult1,
     348        cchEnumResult1,
     349        cchEnumBuffer1
     350    }
     351};
     352
     353/**
     354 * Test the ENUM_PROPS_HOST function.
     355 * @returns iprt status value to indicate whether the test went as expected.
     356 * @note    prints its own diagnostic information to stdout.
     357 */
     358int testEnumPropsHost(VBOXHGCMSVCFNTABLE *ptable)
     359{
     360    int rc = VINF_SUCCESS;
     361    RTPrintf("Testing the ENUM_PROPS_HOST call.\n");
     362    if (!VALID_PTR(ptable->pfnHostCall))
     363    {
     364        RTPrintf("Invalid pfnHostCall() pointer\n");
     365        rc = VERR_INVALID_POINTER;
     366    }
     367    for (unsigned i = 0; RT_SUCCESS(rc) && i < RT_ELEMENTS(enumStrings);
     368         ++i)
     369    {
     370        char buffer[2048];
     371        VBOXHGCMSVCPARM paParms[3];
     372        VBoxHGCMParmPtrSet(&paParms[0],
     373                           (void *) enumStrings[i].pcszPatterns,
     374                           enumStrings[i].cchPatterns);
     375        VBoxHGCMParmPtrSet(&paParms[1],
     376                           (void *) buffer,
     377                           enumStrings[i].cchBuffer - 1);
     378        AssertBreakStmt(sizeof(buffer) > enumStrings[i].cchBuffer,
     379                        rc = VERR_INTERNAL_ERROR);
     380        if (RT_SUCCESS(rc))
     381        {
     382            /* This should fail as the buffer is too small. */
     383            int rc2 = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST,
     384                                          3, paParms);
     385            if (rc2 != VERR_BUFFER_OVERFLOW)
     386            {
     387                RTPrintf("ENUM_PROPS_HOST returned %Rrc instead of VERR_BUFFER_OVERFLOW on too small buffer, pattern number %d\n", rc2, i);
     388                rc = VERR_BUFFER_OVERFLOW;
     389            }
     390            else
     391            {
     392                uint32_t cchBufferActual;
     393                rc = VBoxHGCMParmUInt32Get(&paParms[2], &cchBufferActual);
     394                if (RT_SUCCESS(rc) && cchBufferActual != enumStrings[i].cchBuffer)
     395                {
     396                    RTPrintf("ENUM_PROPS_HOST requested a buffer size of %lu instead of %lu for pattern number %d\n", cchBufferActual, enumStrings[i].cchBuffer, i);
     397                    rc = VERR_OUT_OF_RANGE;
     398                }
     399                else if (RT_FAILURE(rc))
     400                    RTPrintf("ENUM_PROPS_HOST did not return the required buffer size properly for pattern %d\n", i);
     401            }
     402        }
     403        if (RT_SUCCESS(rc))
     404        {
     405            VBoxHGCMParmPtrSet(&paParms[1], (void *) buffer,
     406                               enumStrings[i].cchBuffer);
     407            rc = ptable->pfnHostCall(ptable->pvService, ENUM_PROPS_HOST,
     408                                      3, paParms);
     409            if (RT_FAILURE(rc))
     410                RTPrintf("ENUM_PROPS_HOST call failed for pattern %d with rc=%Rrc\n", i, rc);
     411            else
     412                /* Look for each of the result strings in the buffer which was returned */
     413                for (unsigned j = 0; RT_SUCCESS(rc) && enumStrings[i].ppcchResult[j] != NULL;
     414                     ++j)
     415                {
     416                    bool found = false;
     417                    for (unsigned k = 0; !found && k <   enumStrings[i].cchBuffer
     418                                                       - enumStrings[i].pcchResult[j];
     419                         ++k)
     420                        if (memcmp(buffer + k, enumStrings[i].ppcchResult[j],
     421                            enumStrings[i].pcchResult[j]) == 0)
     422                            found = true;
     423                    if (!found)
     424                    {
     425                        RTPrintf("ENUM_PROPS_HOST did not produce the expected output for pattern %d\n",
     426                                 i);
     427                        rc = VERR_UNRESOLVED_ERROR;
     428                    }
     429                }
     430        }
     431    }
     432    return rc;
     433}
     434
     435/** Array of properties for testing SET_PROP_HOST and _GUEST. */
     436static const struct
     437{
     438    /** Property name */
     439    const char *pcszName;
     440    /** Property value */
     441    const char *pcszValue;
     442    /** Property flags */
     443    const char *pcszFlags;
     444    /** Should this be set as the host or the guest? */
     445    bool isHost;
     446    /** Should we use SET_PROP or SET_PROP_VALUE? */
     447    bool useSetProp;
     448    /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
     449    bool isAllowed;
     450}
     451setProperties[] =
     452{
     453    { "Red", "Stop!", "transient", false, true, true },
     454    { "Amber", "Caution!", "", false, false, true },
     455    { "Green", "Go!", "readonly", true, true, true },
     456    { "Blue", "What on earth...?", "", true, false, true },
     457    { "/test/name", "test", "", false, true, false },
     458    { "TEST NAME", "test", "", true, true, false },
     459    { "Green", "gone out...", "", false, false, false },
     460    { "Green", "gone out...", "", true, false, false },
     461    { NULL, NULL, NULL, false, false, false }
     462};
     463
     464/**
     465 * Test the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST
     466 * functions.
     467 * @returns iprt status value to indicate whether the test went as expected.
     468 * @note    prints its own diagnostic information to stdout.
     469 */
     470int testSetProp(VBOXHGCMSVCFNTABLE *pTable)
     471{
     472    int rc = VINF_SUCCESS;
     473    VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
     474    RTPrintf("Testing the SET_PROP, SET_PROP_VALUE, SET_PROP_HOST and SET_PROP_VALUE_HOST calls.\n");
     475    for (unsigned i = 0; RT_SUCCESS(rc) && (setProperties[i].pcszName != NULL);
     476         ++i)
     477    {
     478        int command = SET_PROP_VALUE;
     479        if (setProperties[i].isHost)
     480        {
     481            if (setProperties[i].useSetProp)
     482                command = SET_PROP_HOST;
     483            else
     484                command = SET_PROP_VALUE_HOST;
     485        }
     486        else if (setProperties[i].useSetProp)
     487            command = SET_PROP;
     488        VBOXHGCMSVCPARM paParms[3];
     489        /* Work around silly constant issues - we ought to allow passing
     490         * constant strings in the hgcm parameters. */
     491        char szName[MAX_NAME_LEN] = "";
     492        char szValue[MAX_VALUE_LEN] = "";
     493        char szFlags[MAX_FLAGS_LEN] = "";
     494        strncat(szName, setProperties[i].pcszName, sizeof(szName));
     495        strncat(szValue, setProperties[i].pcszValue, sizeof(szValue));
     496        strncat(szFlags, setProperties[i].pcszFlags, sizeof(szFlags));
     497        VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1);
     498        VBoxHGCMParmPtrSet(&paParms[1], szValue, strlen(szValue) + 1);
     499        VBoxHGCMParmPtrSet(&paParms[2], szFlags, strlen(szFlags) + 1);
     500        if (setProperties[i].isHost)
     501            callHandle.rc = pTable->pfnHostCall(pTable->pvService, command,
     502                                                setProperties[i].useSetProp
     503                                                    ? 3 : 2, paParms);
     504        else
     505            pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command,
     506                            setProperties[i].useSetProp ? 3 : 2, paParms);
     507        if (setProperties[i].isAllowed && RT_FAILURE(callHandle.rc))
     508        {
     509            RTPrintf("Setting property '%s' failed with rc=%Rrc.\n",
     510                     setProperties[i].pcszName, callHandle.rc);
     511            rc = callHandle.rc;
     512        }
     513        else if (   !setProperties[i].isAllowed
     514                 && (callHandle.rc != VERR_PERMISSION_DENIED)
     515                )
     516        {
     517            RTPrintf("Setting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
     518                     setProperties[i].pcszName, callHandle.rc);
     519            rc = VERR_UNRESOLVED_ERROR;
     520        }
     521    }
     522    return rc;
     523}
     524
     525/** Array of properties for testing DEL_PROP_HOST and _GUEST. */
     526static const struct
     527{
     528    /** Property name */
     529    const char *pcszName;
     530    /** Should this be set as the host or the guest? */
     531    bool isHost;
     532    /** Should this succeed or be rejected with VERR_PERMISSION_DENIED? */
     533    bool isAllowed;
     534}
     535delProperties[] =
     536{
     537    { "Red", false, true },
     538    { "Amber", true, true },
     539    { "Red2", false, true },
     540    { "Amber2", true, true },
     541    { "Green", false, false },
     542    { "Green", true, false },
     543    { "/test/name", false, false },
     544    { "TEST NAME", true, false },
     545    { NULL, false, false }
     546};
     547
     548/**
     549 * Test the DEL_PROP, and DEL_PROP_HOST functions.
     550 * @returns iprt status value to indicate whether the test went as expected.
     551 * @note    prints its own diagnostic information to stdout.
     552 */
     553int testDelProp(VBOXHGCMSVCFNTABLE *pTable)
     554{
     555    int rc = VINF_SUCCESS;
     556    VBOXHGCMCALLHANDLE_TYPEDEF callHandle = { VINF_SUCCESS };
     557    RTPrintf("Testing the DEL_PROP and DEL_PROP_HOST calls.\n");
     558    for (unsigned i = 0; RT_SUCCESS(rc) && (delProperties[i].pcszName != NULL);
     559         ++i)
     560    {
     561        int command = DEL_PROP;
     562        if (delProperties[i].isHost)
     563            command = DEL_PROP_HOST;
     564        VBOXHGCMSVCPARM paParms[1];
     565        /* Work around silly constant issues - we ought to allow passing
     566         * constant strings in the hgcm parameters. */
     567        char szName[MAX_NAME_LEN] = "";
     568        strncat(szName, delProperties[i].pcszName, sizeof(szName));
     569        VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1);
     570        if (delProperties[i].isHost)
     571            callHandle.rc = pTable->pfnHostCall(pTable->pvService, command,
     572                                                1, paParms);
     573        else
     574            pTable->pfnCall(pTable->pvService, &callHandle, 0, NULL, command,
     575                            1, paParms);
     576        if (delProperties[i].isAllowed && RT_FAILURE(callHandle.rc))
     577        {
     578            RTPrintf("Deleting property '%s' failed with rc=%Rrc.\n",
     579                     delProperties[i].pcszName, callHandle.rc);
     580            rc = callHandle.rc;
     581        }
     582        else if (   !delProperties[i].isAllowed
     583                 && (callHandle.rc != VERR_PERMISSION_DENIED)
     584                )
     585        {
     586            RTPrintf("Deleting property '%s' returned %Rrc instead of VERR_PERMISSION_DENIED.\n",
     587                     delProperties[i].pcszName, callHandle.rc);
     588            rc = VERR_UNRESOLVED_ERROR;
     589        }
     590    }
     591    return rc;
     592}
     593
     594/** Array of properties for testing GET_PROP_HOST. */
     595static const struct
     596{
     597    /** Property name */
     598    const char *pcszName;
     599    /** What value/flags pattern do we expect back? */
     600    const char *pcchValue;
     601    /** What size should the value/flags array be? */
     602    uint32_t cchValue;
     603    /** Should this proeprty exist? */
     604    bool exists;
     605    /** Do we expect a particular timestamp? */
     606    bool hasTimestamp;
     607    /** What timestamp if any do ex expect? */
     608    uint64_t u64Timestamp;
     609}
     610getProperties[] =
     611{
     612    { "test/name/", "test/value/\0", sizeof("test/value/\0"), true, true, 0 },
     613    { "test name", "test value\0TRANSIENT, READONLY",
     614      sizeof("test value\0TRANSIENT, READONLY"), true, true, 999 },
     615    { "TEST NAME", "TEST VALUE\0RDONLYHOST", sizeof("TEST VALUE\0RDONLYHOST"),
     616      true, true, 999999 },
     617    { "/test/name", "/test/value\0RDONLYGUEST",
     618      sizeof("/test/value\0RDONLYGUEST"), true, true, 999999999999 },
     619    { "Green", "Go!\0READONLY", sizeof("Go!\0READONLY"), true, false, 0 },
     620    { "Blue", "What on earth...?\0", sizeof("What on earth...?\0"), true,
     621      false, 0 },
     622    { "Red", "", 0, false, false, 0 },
     623    { NULL, NULL, 0, false, false, 0 }
     624};
     625
     626/**
     627 * Test the GET_PROP_HOST function.
     628 * @returns iprt status value to indicate whether the test went as expected.
     629 * @note    prints its own diagnostic information to stdout.
     630 */
     631int testGetProp(VBOXHGCMSVCFNTABLE *pTable)
     632{
     633    int rc = VINF_SUCCESS, rc2 = VINF_SUCCESS;
     634    RTPrintf("Testing the GET_PROP_HOST call.\n");
     635    for (unsigned i = 0; RT_SUCCESS(rc) && (getProperties[i].pcszName != NULL);
     636         ++i)
     637    {
     638        VBOXHGCMSVCPARM paParms[4];
     639        /* Work around silly constant issues - we ought to allow passing
     640         * constant strings in the hgcm parameters. */
     641        char szName[MAX_NAME_LEN] = "";
     642        char szBuffer[MAX_VALUE_LEN + MAX_FLAGS_LEN];
     643        AssertBreakStmt(sizeof(szBuffer) >= getProperties[i].cchValue,
     644                        rc = VERR_INTERNAL_ERROR);
     645        strncat(szName, getProperties[i].pcszName, sizeof(szName));
     646        VBoxHGCMParmPtrSet(&paParms[0], szName, strlen(szName) + 1);
     647        VBoxHGCMParmPtrSet(&paParms[1], szBuffer, sizeof(szBuffer));
     648        rc2 = pTable->pfnHostCall(pTable->pvService, GET_PROP_HOST, 4,
     649                                  paParms);
     650        if (getProperties[i].exists && RT_FAILURE(rc2))
     651        {
     652            RTPrintf("Getting property '%s' failed with rc=%Rrc.\n",
     653                     getProperties[i].pcszName, rc2);
     654            rc = rc2;
     655        }
     656        else if (!getProperties[i].exists && (rc2 != VERR_NOT_FOUND))
     657        {
     658            RTPrintf("Getting property '%s' returned %Rrc instead of VERR_NOT_FOUND.\n",
     659                     getProperties[i].pcszName, rc2);
     660            rc = VERR_UNRESOLVED_ERROR;
     661        }
     662        if (RT_SUCCESS(rc) && getProperties[i].exists)
     663        {
     664            uint32_t u32ValueLen;
     665            rc = VBoxHGCMParmUInt32Get(&paParms[3], &u32ValueLen);
     666            if (RT_FAILURE(rc))
     667                RTPrintf("Failed to get the size of the output buffer for property '%s'\n",
     668                         getProperties[i].pcszName);
     669            if (   RT_SUCCESS(rc)
     670                && (memcmp(szBuffer, getProperties[i].pcchValue,
     671                           getProperties[i].cchValue) != 0)
     672               )
     673            {
     674                RTPrintf("Unexpected result '%.*s' for property '%s', expected '%.*s'.\n",
     675                         u32ValueLen, szBuffer, getProperties[i].pcszName,
     676                         getProperties[i].cchValue, getProperties[i].pcchValue);
     677                rc = VERR_UNRESOLVED_ERROR;
     678            }
     679            if (RT_SUCCESS(rc) && getProperties[i].hasTimestamp)
     680            {
     681                uint64_t u64Timestamp;
     682                rc = VBoxHGCMParmUInt64Get(&paParms[2], &u64Timestamp);
     683                if (RT_FAILURE(rc))
     684                    RTPrintf("Failed to get the timestamp for property '%s'\n",
     685                             getProperties[i].pcszName);
     686                if (   RT_SUCCESS(rc)
     687                    && (u64Timestamp != getProperties[i].u64Timestamp)
     688                   )
     689                {
     690                    RTPrintf("Bad timestamp %llu for property '%s', expected %llu.\n",
     691                             u64Timestamp, getProperties[i].pcszName,
     692                             getProperties[i].u64Timestamp);
     693                    rc = VERR_UNRESOLVED_ERROR;
     694                }
     695            }
     696        }
     697    }
     698    return rc;
     699}
     700
    86701int main(int argc, char **argv)
    87702{
     703    VBOXHGCMSVCFNTABLE svcTable;
     704    VBOXHGCMSVCHELPERS svcHelpers;
     705    initTable(&svcTable, &svcHelpers);
    88706    RTR3Init();
    89707    if (RT_FAILURE(testConvertFlags()))
    90708        return 1;
     709    /* The function is inside the service, not HGCM. */
     710    if (RT_FAILURE(VBoxHGCMSvcLoad(&svcTable)))
     711    {
     712        RTPrintf("Failed to start HGCM service.\n");
     713        return 1;
     714    }
     715    if (RT_FAILURE(testSetPropsHost(&svcTable)))
     716        return 1;
     717    if (RT_FAILURE(testEnumPropsHost(&svcTable)))
     718        return 1;
     719    if (RT_FAILURE(testSetProp(&svcTable)))
     720        return 1;
     721    if (RT_FAILURE(testDelProp(&svcTable)))
     722        return 1;
     723    if (RT_FAILURE(testGetProp(&svcTable)))
     724        return 1;
    91725    RTPrintf("tstGuestPropSvc: SUCCEEDED.\n");
    92726    return 0;
    93727}
    94 
  • trunk/src/VBox/Main/ConsoleImpl.cpp

    r13755 r13759  
    9696#include <algorithm>
    9797#include <memory> // for auto_ptr
     98#include <vector>
    9899
    99100
     
    10621063            rc = VERR_UNRESOLVED_ERROR;  /** @todo translate error code */
    10631064    return rc;
     1065}
     1066
     1067HRESULT Console::doEnumerateGuestProperties (INPTR BSTR aPatterns,
     1068                                             ComSafeArrayOut(BSTR, aNames),
     1069                                             ComSafeArrayOut(BSTR, aValues),
     1070                                             ComSafeArrayOut(ULONG64, aTimestamps),
     1071                                             ComSafeArrayOut(BSTR, aFlags))
     1072{
     1073    using namespace guestProp;
     1074
     1075    VBOXHGCMSVCPARM parm[3];
     1076
     1077    Utf8Str utf8Patterns(aPatterns);
     1078    parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
     1079    parm[0].u.pointer.addr = utf8Patterns.mutableRaw();
     1080    parm[0].u.pointer.size = utf8Patterns.length() + 1;
     1081
     1082    /*
     1083     * Now things get slightly complicated.  Due to a race with the guest adding
     1084     * properties, there is no good way to know how much large a buffer to provide
     1085     * the service to enumerate into.  We choose a decent starting size and loop a
     1086     * few times, each time retrying with the size suggested by the service plus
     1087     * one Kb.
     1088     */
     1089    size_t cchBuf = 4096;
     1090    Utf8Str Utf8Buf;
     1091    int vrc = VERR_BUFFER_OVERFLOW;
     1092    for (unsigned i = 0; i < 10 && (VERR_BUFFER_OVERFLOW == vrc); ++i)
     1093    {
     1094        Utf8Buf.alloc(cchBuf + 1024);
     1095        if (Utf8Buf.isNull())
     1096            return E_OUTOFMEMORY;
     1097        parm[1].type = VBOX_HGCM_SVC_PARM_PTR;
     1098        parm[1].u.pointer.addr = Utf8Buf.mutableRaw();
     1099        parm[1].u.pointer.size = cchBuf + 1024;
     1100        vrc = mVMMDev->hgcmHostCall ("VBoxGuestPropSvc", ENUM_PROPS_HOST, 3,
     1101                                     &parm[0]);
     1102        if (parm[2].type != VBOX_HGCM_SVC_PARM_32BIT)
     1103            return setError (E_FAIL, tr ("Internal application error"));
     1104        cchBuf = parm[2].u.uint32;
     1105    }
     1106    if (VERR_BUFFER_OVERFLOW == vrc)
     1107        return setError (E_UNEXPECTED, tr ("Temporary failure due to guest activity, please retry"));
     1108
     1109    /*
     1110     * Finally we have to unpack the data returned by the service into the safe
     1111     * arrays supplied by the caller.  We start by counting the number of entries.
     1112     */
     1113    const char *pszBuf
     1114        = reinterpret_cast<const char *>(parm[1].u.pointer.addr);
     1115    unsigned cEntries = 0;
     1116    /* The list is terminated by a zero-length string at the end of a set
     1117     * of four strings. */
     1118    for (size_t i = 0; strlen(pszBuf + i) != 0; )
     1119    {
     1120       /* We are counting sets of four strings. */
     1121       for (unsigned j = 0; j < 4; ++j)
     1122           i += strlen(pszBuf + i) + 1;
     1123       ++cEntries;
     1124    }
     1125
     1126    /*
     1127     * And now we create the COM safe arrays and fill them in.
     1128     */
     1129    com::SafeArray <BSTR> names(cEntries);
     1130    com::SafeArray <BSTR> values(cEntries);
     1131    com::SafeArray <ULONG64> timestamps(cEntries);
     1132    com::SafeArray <BSTR> flags(cEntries);
     1133    size_t iBuf = 0;
     1134    /* Rely on the service to have formated the data correctly. */
     1135    for (unsigned i = 0; i < cEntries; ++i)
     1136    {
     1137        size_t cchName = strlen(pszBuf + iBuf);
     1138        Bstr(pszBuf + iBuf).detachTo(&names[i]);
     1139        iBuf += cchName + 1;
     1140        size_t cchValue = strlen(pszBuf + iBuf);
     1141        Bstr(pszBuf + iBuf).detachTo(&values[i]);
     1142        iBuf += cchValue + 1;
     1143        size_t cchTimestamp = strlen(pszBuf + iBuf);
     1144        timestamps[i] = RTStrToUInt64(pszBuf + iBuf);
     1145        iBuf += cchTimestamp + 1;
     1146        size_t cchFlags = strlen(pszBuf + iBuf);
     1147        Bstr(pszBuf + iBuf).detachTo(&flags[i]);
     1148        iBuf += cchFlags + 1;
     1149    }
     1150    names.detachTo(ComSafeArrayOutArg (aNames));
     1151    values.detachTo(ComSafeArrayOutArg (aValues));
     1152    timestamps.detachTo(ComSafeArrayOutArg (aTimestamps));
     1153    flags.detachTo(ComSafeArrayOutArg (aFlags));
     1154    return S_OK;
    10641155}
    10651156#endif
     
    36873778     * autoVMCaller, so there is no need to hold a lock of this */
    36883779
    3689     using namespace guestProp;
    3690 
    3691     VBOXHGCMSVCPARM parm[3];
    3692 
    3693     Utf8Str utf8Patterns(aPatterns);
    3694     parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
    3695     parm[0].u.pointer.addr = utf8Patterns.mutableRaw();
    3696     parm[0].u.pointer.size = utf8Patterns.length() + 1;
    3697 
    3698     /*
    3699      * Now things get slightly complicated.  Due to a race with the guest adding
    3700      * properties, there is no good way to know how much large a buffer to provide
    3701      * the service to enumerate into.  We choose a decent starting size and loop a
    3702      * few times, each time retrying with the size suggested by the service plus
    3703      * one Kb.
    3704      */
    3705     size_t cchBuf = 4096;
    3706     Utf8Str Utf8Buf;
    3707     int vrc = VERR_BUFFER_OVERFLOW;
    3708     for (unsigned i = 0; i < 10 && (VERR_BUFFER_OVERFLOW == vrc); ++i)
    3709     {
    3710         Utf8Buf.alloc(cchBuf + 1024);
    3711         if (Utf8Buf.isNull())
    3712             return E_OUTOFMEMORY;
    3713         parm[1].type = VBOX_HGCM_SVC_PARM_PTR;
    3714         parm[1].u.pointer.addr = Utf8Buf.mutableRaw();
    3715         parm[1].u.pointer.size = cchBuf + 1024;
    3716         vrc = mVMMDev->hgcmHostCall ("VBoxGuestPropSvc", ENUM_PROPS_HOST, 3,
    3717                                      &parm[0]);
    3718         if (parm[2].type != VBOX_HGCM_SVC_PARM_32BIT)
    3719             return setError (E_FAIL, tr ("Internal application error"));
    3720         cchBuf = parm[2].u.uint32;
    3721     }
    3722     if (VERR_BUFFER_OVERFLOW == vrc)
    3723         return setError (E_UNEXPECTED, tr ("Temporary failure due to guest activity, please retry"));
    3724 
    3725     /*
    3726      * Finally we have to unpack the data returned by the service into the safe
    3727      * arrays supplied by the caller.  We start by counting the number of entries.
    3728      */
    3729     const char *pszBuf
    3730         = reinterpret_cast<const char *>(parm[1].u.pointer.addr);
    3731     unsigned cEntries = 0;
    3732     /* The list is terminated by a zero-length string at the end of a set
    3733      * of four strings. */
    3734     for (size_t i = 0; strlen(pszBuf + i) != 0; )
    3735     {
    3736        /* We are counting sets of four strings. */
    3737        for (unsigned j = 0; j < 4; ++j)
    3738            i += strlen(pszBuf + i) + 1;
    3739        ++cEntries;
    3740     }
    3741 
    3742     /*
    3743      * And now we create the COM safe arrays and fill them in.
    3744      */
    3745     com::SafeArray <BSTR> names(cEntries);
    3746     com::SafeArray <BSTR> values(cEntries);
    3747     com::SafeArray <ULONG64> timestamps(cEntries);
    3748     com::SafeArray <BSTR> flags(cEntries);
    3749     size_t iBuf = 0;
    3750     /* Rely on the service to have formated the data correctly. */
    3751     for (unsigned i = 0; i < cEntries; ++i)
    3752     {
    3753         size_t cchName = strlen(pszBuf + iBuf);
    3754         Bstr(pszBuf + iBuf).detachTo(&names[i]);
    3755         iBuf += cchName + 1;
    3756         size_t cchValue = strlen(pszBuf + iBuf);
    3757         Bstr(pszBuf + iBuf).detachTo(&values[i]);
    3758         iBuf += cchValue + 1;
    3759         size_t cchTimestamp = strlen(pszBuf + iBuf);
    3760         timestamps[i] = RTStrToUInt64(pszBuf + iBuf);
    3761         iBuf += cchTimestamp + 1;
    3762         size_t cchFlags = strlen(pszBuf + iBuf);
    3763         Bstr(pszBuf + iBuf).detachTo(&flags[i]);
    3764         iBuf += cchFlags + 1;
    3765     }
    3766     names.detachTo(ComSafeArrayOutArg (aNames));
    3767     values.detachTo(ComSafeArrayOutArg (aValues));
    3768     timestamps.detachTo(ComSafeArrayOutArg (aTimestamps));
    3769     flags.detachTo(ComSafeArrayOutArg (aFlags));
    3770     return S_OK;
     3780    return doEnumerateGuestProperties (aPatterns, ComSafeArrayOutArg(aNames),
     3781                                       ComSafeArrayOutArg(aValues),
     3782                                       ComSafeArrayOutArg(aTimestamps),
     3783                                       ComSafeArrayOutArg(aFlags));
    37713784#endif /* else !defined (VBOX_WITH_GUEST_PROPS) */
    37723785}
     
    46334646#ifdef VBOX_WITH_HGCM
    46344647
     4648# ifdef VBOX_WITH_GUEST_PROPS
     4649
     4650    /* Save all guest property store entries to the machine XML file */
     4651    com::SafeArray <BSTR> namesOut;
     4652    com::SafeArray <BSTR> valuesOut;
     4653    com::SafeArray <ULONG64> timestampsOut;
     4654    com::SafeArray <BSTR> flagsOut;
     4655    Bstr pattern("");
     4656    if (pattern.isNull())
     4657        rc = E_OUTOFMEMORY;
     4658    else
     4659        rc = doEnumerateGuestProperties (Bstr (""), ComSafeArrayAsOutParam (namesOut),
     4660                                        ComSafeArrayAsOutParam (valuesOut),
     4661                                        ComSafeArrayAsOutParam (timestampsOut),
     4662                                        ComSafeArrayAsOutParam (flagsOut));
     4663    if (SUCCEEDED(rc))
     4664    {
     4665        try
     4666        {
     4667            std::vector <BSTR> names;
     4668            std::vector <BSTR> values;
     4669            std::vector <ULONG64> timestamps;
     4670            std::vector <BSTR> flags;
     4671            for (unsigned i = 0; i < namesOut.size(); ++i)
     4672            {
     4673                uint32_t fFlags;
     4674                guestProp::validateFlags (Utf8Str(flagsOut[i]).raw(), &fFlags);
     4675                if (   !( fFlags & guestProp::TRANSIENT)
     4676                    || (mMachineState == MachineState_Saving)
     4677                  )
     4678                {
     4679                    names.push_back(namesOut[i]);
     4680                    values.push_back(valuesOut[i]);
     4681                    timestamps.push_back(timestampsOut[i]);
     4682                    flags.push_back(flagsOut[i]);
     4683                }
     4684            }
     4685            com::SafeArray <BSTR> namesIn (names);
     4686            com::SafeArray <BSTR> valuesIn (values);
     4687            com::SafeArray <ULONG64> timestampsIn (timestamps);
     4688            com::SafeArray <BSTR> flagsIn (flags);
     4689            if (   namesIn.isNull()
     4690                || valuesIn.isNull()
     4691                || timestampsIn.isNull()
     4692                || flagsIn.isNull()
     4693                )
     4694                throw std::bad_alloc();
     4695            /* PushGuestProperties() calls DiscardSettings(), which calls us back */
     4696            alock.leave();
     4697            mControl->PushGuestProperties (ComSafeArrayAsInParam (namesIn),
     4698                                          ComSafeArrayAsInParam (valuesIn),
     4699                                          ComSafeArrayAsInParam (timestampsIn),
     4700                                          ComSafeArrayAsInParam (flagsIn));
     4701            alock.enter();
     4702        }
     4703        catch (std::bad_alloc)
     4704        {
     4705            rc = E_OUTOFMEMORY;
     4706        }
     4707    }
     4708
     4709    /* advance percent count */
     4710    if (aProgress)
     4711        aProgress->notifyProgress (99 * (++ step) / StepCount );
     4712
     4713# endif /* VBOX_WITH_GUEST_PROPS defined */
     4714
    46354715    /* Shutdown HGCM services before stopping the guest, because they might
    46364716     * need a cleanup. */
     
    46504730    if (aProgress)
    46514731        aProgress->notifyProgress (99 * (++ step) / StepCount );
    4652 
    4653 # ifdef VBOX_WITH_GUEST_PROPS
    4654 
    4655     /* Save all guest property store entries to the machine XML file */
    4656     PCFGMNODE pValues = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Values/");
    4657     PCFGMNODE pTimestamps = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Timestamps/");
    4658     PCFGMNODE pFlags = CFGMR3GetChild (CFGMR3GetRoot (mpVM), "GuestProps/Flags/");
    4659 
    4660     /* Count the number of entries we have */
    4661     unsigned cValues = 0;
    4662     PCFGMLEAF pValue;
    4663     for (pValue = CFGMR3GetFirstValue (pValues); pValue != NULL;
    4664          pValue = CFGMR3GetNextValue (pValue))
    4665     {
    4666         char szPropName[guestProp::MAX_NAME_LEN];
    4667         vrc = CFGMR3GetValueName (pValue, szPropName, sizeof(szPropName));
    4668         if (RT_SUCCESS(vrc))
    4669         {
    4670             /* Do not send transient properties unless we are saving state */
    4671             uint32_t fFlags = guestProp::NILFLAG;
    4672             CFGMR3QueryU32 (pFlags, szPropName, &fFlags);
    4673             if (!(fFlags & guestProp::TRANSIENT) ||
    4674                 (mMachineState == MachineState_Saving))
    4675                 ++cValues;
    4676         }
    4677     }
    4678 
    4679     /* And pack them into safe arrays */
    4680     com::SafeArray <BSTR> names(cValues);
    4681     com::SafeArray <BSTR> values(cValues);
    4682     com::SafeArray <ULONG64> timestamps(cValues);
    4683     com::SafeArray <BSTR> flags(cValues);
    4684     pValue = CFGMR3GetFirstValue (pValues);
    4685 
    4686     vrc = VINF_SUCCESS;
    4687     unsigned iProp = 0;
    4688     while (pValue != NULL && RT_SUCCESS (vrc))
    4689     {
    4690         using namespace guestProp;
    4691 
    4692         char szPropName [MAX_NAME_LEN];
    4693         char szPropValue [MAX_VALUE_LEN];
    4694         char szPropFlags [MAX_FLAGS_LEN];
    4695         ULONG64 u64Timestamp = 0;  /* default */
    4696         vrc = CFGMR3GetValueName (pValue, szPropName, sizeof (szPropName));
    4697         if (RT_SUCCESS(vrc))
    4698             vrc = CFGMR3QueryString (pValues, szPropName, szPropValue,
    4699                                      sizeof (szPropValue));
    4700         if (RT_SUCCESS(vrc))
    4701         {
    4702             uint32_t fFlags = NILFLAG;
    4703             CFGMR3QueryU32 (pFlags, szPropName, &fFlags);
    4704             /* Skip transient properties unless we are saving state */
    4705             if (!(fFlags & TRANSIENT) ||
    4706                 (mMachineState == MachineState_Saving))
    4707             {
    4708                 writeFlags(fFlags, szPropFlags);
    4709                 CFGMR3QueryU64 (pTimestamps, szPropName, &u64Timestamp);
    4710                 Bstr(szPropName).cloneTo(&names[iProp]);
    4711                 Bstr(szPropValue).cloneTo(&values[iProp]);
    4712                 timestamps[iProp] = u64Timestamp;
    4713                 Bstr(szPropFlags).cloneTo(&flags[iProp]);
    4714                 ++iProp;
    4715                 if (iProp >= cValues)
    4716                     vrc = VERR_TOO_MUCH_DATA;
    4717             }
    4718             pValue = CFGMR3GetNextValue (pValue);
    4719         }
    4720     }
    4721 
    4722     if (RT_SUCCESS(vrc) || (VERR_TOO_MUCH_DATA == vrc))
    4723     {
    4724         /* PushGuestProperties() calls DiscardSettings(), which calls us back */
    4725         alock.leave();
    4726         mControl->PushGuestProperties (ComSafeArrayAsInParam (names),
    4727                                        ComSafeArrayAsInParam (values),
    4728                                        ComSafeArrayAsInParam (timestamps),
    4729                                        ComSafeArrayAsInParam (flags));
    4730         alock.enter();
    4731     }
    4732 
    4733     /* advance percent count */
    4734     if (aProgress)
    4735         aProgress->notifyProgress (99 * (++ step) / StepCount );
    4736 
    4737 # endif /* VBOX_WITH_GUEST_PROPS defined */
    47384732
    47394733#endif /* VBOX_WITH_HGCM */
  • trunk/src/VBox/Main/ConsoleImpl2.cpp

    r13722 r13759  
    5151# include <hgcm/HGCM.h> /** @todo it should be possible to register a service
    5252                          * extension using a VMMDev callback. */
     53# include <vector>
    5354#endif /* VBOX_WITH_GUEST_PROPS */
    5455#include <VBox/intnet.h>
     
    269270    PCFGMNODE pSataInst = NULL;     /* /Devices/ahci/0/ */
    270271        PCFGMNODE pBiosCfg = NULL;      /* /Devices/pcbios/0/Config/ */
    271 #ifdef VBOX_WITH_GUEST_PROPS
    272     PCFGMNODE pGuestProps = NULL;   /* /GuestProps */
    273     PCFGMNODE pValues = NULL;       /* /GuestProps/Values */
    274     PCFGMNODE pTimestamps = NULL;   /* /GuestProps/Timestamps */
    275     PCFGMNODE pFlags = NULL;        /* /GuestProps/Flags */
    276 #endif /* VBOX_WITH_GUEST_PROPS defined */
    277272
    278273    rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices);                             RC_CHECK();
     
    17291724#ifdef VBOX_WITH_GUEST_PROPS
    17301725    /*
    1731      * Shared information services
     1726     * Guest property service
    17321727     */
    17331728    {
     
    17431738        else
    17441739        {
    1745             rc = CFGMR3InsertNode(pRoot,       "GuestProps", &pGuestProps);             RC_CHECK();
    1746             rc = CFGMR3InsertNode(pGuestProps, "Values", &pValues);                     RC_CHECK();
    1747             rc = CFGMR3InsertNode(pGuestProps, "Timestamps", &pTimestamps);             RC_CHECK();
    1748             rc = CFGMR3InsertNode(pGuestProps, "Flags", &pFlags);                       RC_CHECK();
    1749 
    17501740            /* Pull over the properties from the server. */
    1751             SafeArray <BSTR> names;
    1752             SafeArray <BSTR> values;
    1753             SafeArray <ULONG64> timestamps;
    1754             SafeArray <BSTR> flags;
    1755             hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(names),
    1756                                                 ComSafeArrayAsOutParam(values),
    1757                                                 ComSafeArrayAsOutParam(timestamps),
    1758                                                 ComSafeArrayAsOutParam(flags));         H();
    1759             size_t cProps = names.size();
    1760             for (size_t i = 0; i < cProps; ++i)
    1761             {
    1762                 rc = CFGMR3InsertString(pValues, Utf8Str(names[i]).raw(), Utf8Str(values[i]).raw());    RC_CHECK();
    1763                 rc = CFGMR3InsertInteger(pTimestamps, Utf8Str(names[i]).raw(), timestamps[i]);          RC_CHECK();
    1764                 uint32_t fFlags;
    1765                 rc = guestProp::validateFlags(Utf8Str(flags[i]).raw(), &fFlags);
    1766                 AssertLogRelRCReturn(rc, VMSetError(pVM, VERR_INVALID_PARAMETER, RT_SRC_POS,
    1767                     N_("Guest property '%lS' has invalid flags '%lS' in machine definition file"),
    1768                        names[i], flags[i]));
    1769                 rc = CFGMR3InsertInteger(pFlags, Utf8Str(names[i]).raw(), fFlags);                      RC_CHECK();
    1770             }
     1741            SafeArray <BSTR> namesOut;
     1742            SafeArray <BSTR> valuesOut;
     1743            SafeArray <ULONG64> timestampsOut;
     1744            SafeArray <BSTR> flagsOut;
     1745            hrc = pConsole->mControl->PullGuestProperties(ComSafeArrayAsOutParam(namesOut),
     1746                                                ComSafeArrayAsOutParam(valuesOut),
     1747                                                ComSafeArrayAsOutParam(timestampsOut),
     1748                                                ComSafeArrayAsOutParam(flagsOut));         H();
     1749            size_t cProps = namesOut.size();
     1750            if (   valuesOut.size() != cProps
     1751                || timestampsOut.size() != cProps
     1752                || flagsOut.size() != cProps
     1753               )
     1754                rc = VERR_INVALID_PARAMETER;
     1755
     1756            std::vector <Utf8Str> utf8Names, utf8Values, utf8Flags;
     1757            std::vector <char *> names, values, flags;
     1758            std::vector <ULONG64> timestamps;
     1759            for (unsigned i = 0; i < cProps && RT_SUCCESS(rc); ++i)
     1760                if (   !VALID_PTR(namesOut[i])
     1761                    || !VALID_PTR(valuesOut[i])
     1762                    || !VALID_PTR(flagsOut[i])
     1763                   )
     1764                    rc = VERR_INVALID_POINTER;
     1765            for (unsigned i = 0; i < cProps && RT_SUCCESS(rc); ++i)
     1766            {
     1767                utf8Names.push_back(Bstr(namesOut[i]));
     1768                utf8Values.push_back(Bstr(valuesOut[i]));
     1769                timestamps.push_back(timestampsOut[i]);
     1770                utf8Flags.push_back(Bstr(flagsOut[i]));
     1771                if (   utf8Names.back().isNull()
     1772                    || utf8Values.back().isNull()
     1773                    || utf8Flags.back().isNull()
     1774                   )
     1775                    throw std::bad_alloc();
     1776            }
     1777            for (unsigned i = 0; i < cProps && RT_SUCCESS(rc); ++i)
     1778            {
     1779                names.push_back(utf8Names[i].mutableRaw());
     1780                values.push_back(utf8Values[i].mutableRaw());
     1781                flags.push_back(utf8Flags[i].mutableRaw());
     1782            }
     1783            names.push_back(NULL);
     1784            values.push_back(NULL);
     1785            timestamps.push_back(0);
     1786            flags.push_back(NULL);
    17711787
    17721788            /* Setup the service. */
    1773             VBOXHGCMSVCPARM parms[3];
     1789            VBOXHGCMSVCPARM parms[4];
    17741790
    17751791            parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
    1776             parms[0].u.pointer.addr = pValues;
    1777             parms[0].u.pointer.size = sizeof(pValues);  /* We don't actually care. */
     1792            parms[0].u.pointer.addr = &names.front();
     1793            parms[0].u.pointer.size = 0;  /* We don't actually care. */
    17781794            parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
    1779             parms[1].u.pointer.addr = pTimestamps;
    1780             parms[1].u.pointer.size = sizeof(pTimestamps);
     1795            parms[1].u.pointer.addr = &values.front();
     1796            parms[1].u.pointer.size = 0;  /* We don't actually care. */
    17811797            parms[2].type = VBOX_HGCM_SVC_PARM_PTR;
    1782             parms[2].u.pointer.addr = pFlags;
    1783             parms[2].u.pointer.size = sizeof(pFlags);
    1784 
    1785             pConsole->mVMMDev->hgcmHostCall ("VBoxGuestPropSvc", guestProp::SET_CFGM_NODE, 3, &parms[0]);
     1798            parms[2].u.pointer.addr = &timestamps.front();
     1799            parms[2].u.pointer.size = 0;  /* We don't actually care. */
     1800            parms[3].type = VBOX_HGCM_SVC_PARM_PTR;
     1801            parms[3].u.pointer.addr = &flags.front();
     1802            parms[3].u.pointer.size = 0;  /* We don't actually care. */
     1803
     1804            pConsole->mVMMDev->hgcmHostCall ("VBoxGuestPropSvc", guestProp::SET_PROPS_HOST, 4, &parms[0]);
    17861805
    17871806            /* Register the host notification callback */
  • trunk/src/VBox/Main/MachineImpl.cpp

    r13723 r13759  
    30853085            mHWData->mGuestProperties.push_back(property);
    30863086        }
     3087        if (   SUCCEEDED (rc)
     3088            && (   matchAll
     3089                || RTStrSimplePatternMultiMatch (utf8Patterns.raw(), RTSTR_MAX,
     3090                                                utf8Name.raw(), RTSTR_MAX, NULL)
     3091              )
     3092          )
     3093            mParent->onGuestPropertyChange (mData->mUuid, aName, aValue, aFlags);
    30873094    }
    30883095    else
     
    31003107                                                 &dummy, &dummy64, &dummy);
    31013108    }
    3102     if (   SUCCEEDED (rc)
    3103         && (   matchAll
    3104             || RTStrSimplePatternMultiMatch (utf8Patterns.raw(), RTSTR_MAX,
    3105                                              utf8Name.raw(), RTSTR_MAX, NULL)
    3106            )
    3107        )
    3108         mParent->onGuestPropertyChange (mData->mUuid, aName, aValue, aFlags);
    31093109    return rc;
    31103110#endif /* else !defined (VBOX_WITH_GUEST_PROPS) */
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r13606 r13759  
    494494    static DECLCALLBACK(int)    doGuestPropNotification (void *pvExtension, uint32_t,
    495495                                                         void *pvParms, uint32_t cbParms);
     496    HRESULT doEnumerateGuestProperties (INPTR BSTR aPatterns,
     497                                        ComSafeArrayOut(BSTR, aNames),
     498                                        ComSafeArrayOut(BSTR, aValues),
     499                                        ComSafeArrayOut(ULONG64, aTimestamps),
     500                                        ComSafeArrayOut(BSTR, aFlags));
    496501#endif
    497502
Note: See TracChangeset for help on using the changeset viewer.

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